zoukankan      html  css  js  c++  java
  • 重构指南

    封装就是将相关的方法或者属性抽象成为一个对象。

    封装的意义:

    1. 对外隐藏内部实现,接口不变,内部实现自由修改。
    2. 只返回需要的数据和方法。
    3. 提供一种方式防止数据被修改。
    4. 更好的代码复用。
    当一个类的属性类型为集合,或者方法返回类型为集合时,如果符合以下条件,我们就可以考虑将集合进行封装:
    1. 返回的数据仅用于展示
    2. 当集合的Add,Remove方法包含其它业务逻辑
    向类的调用者隐藏类中的完整集合有如下几个好处:
    1. 保证返回的集合数据不会被修改。
    2. 在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。
  • 相关阅读:
    算法练习(16)-水平翻转一颗二叉树
    算法练习(15)-设计1个二叉树的序列化与反序列化实现?
    算法练习(14)-二叉树中2个节点的最近公共祖先?
    算法练习(13)-打印纸条对折的折痕类型(凹痕?凸痕?)
    算法练习(12)-二叉树的递归套路
    算法练习(11)-二叉树的各种遍历
    算法练习(10)-求2个(可能有环的)单链表的相交节点
    算法练习(9)-复杂带随机指针的单链表
    mac升级后第三方下载程序无法打开cannot be opened because the developer cannot be verified的解决办法
    算法练习(8)-判断单链表是否回文链表
  • 原文地址:https://www.cnblogs.com/hmloo/p/EncapsulateCollection.html
Copyright © 2011-2022 走看看