封裝就是將相關的方法或者屬性抽象成為一個對象。 封裝的意義: 當一個類的屬性類型為集合,或者方法返回類型為集合時,如果符合以下條件,我們就可以考慮將集合進行封裝: 返回的數據僅用於展示 當集合的Add,Remove方法包含其它業務邏輯 向類的調用者隱藏類中的完整集合有如下幾個好處: 保證返回的集合數 ...
封裝就是將相關的方法或者屬性抽象成為一個對象。
封裝的意義:
- 對外隱藏內部實現,介面不變,內部實現自由修改。
- 只返回需要的數據和方法。
- 提供一種方式防止數據被修改。
- 更好的代碼復用。
- 返回的數據僅用於展示
- 當集合的Add,Remove方法包含其它業務邏輯
- 保證返回的集合數據不會被修改。
- 在Add, Remove方法中可以添加驗證,日誌或其他業務邏輯。
using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.Before { public class Order { private List<OrderLine> _orderLines; private double _orderTotal; public IList<OrderLine> OrderLines { get { return _orderLines; } } public void AddOrderLine(OrderLine orderLine) { _orderTotal += orderLine.Total; _orderLines.Add(orderLine); } public void RemoveOrderLine(OrderLine orderLine) { orderLine = _orderLines.Find(o => o == orderLine); if (orderLine == null) return; _orderTotal -= orderLine.Total; _orderLines.Remove(orderLine); } } public class OrderLine { public double Total { get; private set; } } }上面的代碼在Add或者Remove orderLine時存在業務邏輯,如果調用時直接修改OrderLines的元素,就會產生bug,所以需要重構如下:
using System.Collections.Generic; namespace LosTechies.DaysOfRefactoring.EncapsulateCollection.After { public class Order { private List<OrderLine> _orderLines; private double _orderTotal; //方法一:返回IEnumerable類型 public IEnumerable<OrderLine> OrderLines { get { return _orderLines.Skip(0); } } //方法二:返回只讀類型 public ReadOnlyCollection<OrderLine> OrderLines { get { return _orderLines.AsReadOnly(); } } public void AddOrderLine(OrderLine orderLine) { _orderTotal += orderLine.Total; _orderLines.Add(orderLine); } public void RemoveOrderLine(OrderLine orderLine) { orderLine = _orderLines.Find(o => o == orderLine); if (orderLine == null) return; _orderTotal -= orderLine.Total; _orderLines.Remove(orderLine); } } public class OrderLine { public double Total { get; private set; } } }註意:雖然直接返回IEnumerable,這樣只能遍歷取出它的值,但是還是可以通過轉換為List後操作集合中的元素,所以我們採用_orderLines.Skip(0)迭代返回,這樣就能阻止調用者轉換為list。