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。
  • 相关阅读:
    centos7配置ntp服务器和客户端同步
    搭建Loki、Promtail、Grafana轻量级日志系统(centos7)
    DBLink实现备份文件不落盘的导入其他Oracle数据库实例的方法
    jumpserver使用docker安装
    shellwhile循环读取文件内容
    WEB数据挖掘(八)——Aperture数据抽取(4):Aperture整体结构
    WEB数据挖掘(十)——Aperture数据抽取(6):在Aperture中使用RDF2Go
    matlab练习程序(五次多项式轨迹规划)
    Android与Windows 7比拼悄然开始
    谷歌称年底前至少有18款Android手机上市
  • 原文地址:https://www.cnblogs.com/hmloo/p/EncapsulateCollection.html
Copyright © 2011-2022 走看看