iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Software Development

在Kata中尋找Clean Code是否搞錯了什麼系列 第 24

Day 24 建構子的職責

昨天有稍微提到了一個反例:把方法共同的參數放在建構子傳入,在上禮拜的工廠方法的主題中,也提到了可以使用工廠方法來取代建構子,不知道有沒有人好奇那建構子要拿來做什麼呢?今天我們就來聊聊建構子應該做哪些事情。

我們繼續使用昨天的ReverseExpression的例子,可以發現我們把term移出之後,BinaryExpression也沒有必要隨著迴圈每次重建。而且比起放在方法裡面,他其實更適合放在建構子裡面,讓所有方法都可以使用。

public class ReverseExpression
{
    public double Evaluate(string expression)
    {
        var terms = new Stack<double>();
        foreach (var term in expression.Split(' '))
        {
            var binaryExpression = new BinaryExpression();
            if (binaryExpression.IsValidOperator(term))
            {
                terms.Push(binaryExpression.Calculate(term, terms.Pop(), terms.Pop()));
            }
            else
            {
                terms.Push(double.Parse(term));
            }
        }

        return terms.First();
    }
}

是不是覺得又與昨天提到的有點矛盾了呢?

適合使用建構子的情境

  1. 使用建構子初始化相依物件

    • 相依物件通常會被保存在目標物件的私有欄位中直到目標物件被回收。以上面的例子來說,目標物件是ReverseExpression,而與他相依的物件是BinaryExpression,計算ReverseExpression需要BinaryExpression的協作。BinaryExpression只控制如何計算,但不是改變這個方法輸出的主要變因,影響輸出的主要變因是方法參數。
    • 更進一步的通常會讓BinaryExpression從ReverseExpression的建構子傳入,讓目標物件不直接依賴於BinaryExpression,可以透過建構子抽換BinaryExpression的實作。這也是SOLID原則中的依賴反轉原則,這邊以後如果有機會在解釋更多。
    public class ReverseExpression
    {
        private readonly BinaryExpression _binaryExpression;
    
        public ReverseExpression(BinaryExpression binaryExpression)
        {
            _binaryExpression = binaryExpression;
        }
    
        ...
    }
    
  2. 初始化物件狀態

    • 這種場景通常比較簡單,且使用場景與之前提到的工廠方法的使用情境一致,。例如
      1. 從Remote API收到Response時,我們會把它轉換成商業邏輯使用的Model

        public class UserInfo
        {
        		public int UserId {get; set;}
        
        		public int UserName {get; set;}
        
        		public string Avatar {get; set;}
        
        		...
        
        		public UserInfo(GetUserInfoResponse getUserInfoResponse)
        		{
        				UserInfo = userInfoResponse.UserId;
        				UserName = userInfoResponse.UserName;
        				Avatar = userInfoResponse.Avatar;
        
        				...
        		}
        }
        
      2. 另一種是從兩個Model組出另外一個Model,通常使用這種這做法時,建構子裡頭會包含一些簡單的計算來初始化狀態。

        public class Order 
        {
        		public int UserId {get; set;}
        
        		public int GoodsId {get; set;}
        
        		public decimal Price {get; set;}
        
        		public DateTime OrderDate {get; set;}
        
        		...
        
        		public Order(User user, Goods goods)
        		{
        				UserId = user.Id;
        				GoodsId = goods.Id;
        				Price = goods.price;
        				OrderDate = DateTime.Now;
        
        				...
        		}
        }
        

上一篇
Day 23 方法名稱與參數
下一篇
Day 25 網路上的代碼
系列文
在Kata中尋找Clean Code是否搞錯了什麼30

尚未有邦友留言

立即登入留言