• 第3章 在对象之间搬移特性(1):搬移函数和字段


    1. 搬移函数(Move Method)

    1.1 动机

    (1)某函数与其所驻类之外的另一个类进行更多交流(调用后者或被后者调用),这时可以在后者中建立一个类似行为的新函数。将旧函数变成一个委托函数或将其完全移除。

    (2)当类中存在这样的函数:使用另一个对象的次数比使用自己所驻对象的次数还多,这时可以考虑将函数搬移到另一个对象中。

    1.2 做法

    (1)检查源类中被源函数所使用的一切特性(包括字段和函数),考虑它们是否也该被搬移。如果某个特性只被你打算搬移的那个函数用到,就应该将它一并搬移。如果另有其他函数使用了这个特性,可以考虑将使用该特性的所有函数全都一并搬移。

    (2)检查源类中的子类或父类,看看是否有该函数的其他声明。如果出现其他声明,可能就无法进行搬移,除非目标类也同样表现出多态性。

    (3)在目标类中声明这个函数(可以为此函数选择一个新名称)

    (4)将源函数的代码复制到目标函数中。调整后者,使用能在新的类中正常运行。如果目标函数使用了源类中的特性,可以将源对象当作参数,传递给新的目标函数

    (5)决定如何从源函数正确引用目标对象。(如,可在源类中新建一个字段来保存目标对象)

    (6)修改源函数,使之成为一个纯委托函数。

    (7)决定是否删除源函数,或将它当作一个委托函数保留下来。如果要移除源函数,还得将源类中所有对源函数的调用,替换为对目标函数的调用。

    1.3 范例

    //搬移函数
    //重构前
    class Account
    {
    private:
        AccountType _type; //账户类型
        int _daysOverdrawn;
    public:
        //每种账户都有自己的“透支金额计费规则”,该函数可
        //被搬移到AccoutType类中去。
        double overdraftCharge()
        {
            if(_type.isPremium())
            {
                double result = 10;
                if(_daysOverdrawn > 7)
                    result += (_daysOverdrawn - 7) * 0.85;
                
                return result;
            }
            else
            {
                return _daysOverdrawn * 1.75;
            }            
        }
    };
    
    //重构中
    //1. 观察overdraftCharge()使用的每一项特性,考虑是否将它们与
    //该函数一起被搬移。本例中_daysOverdrawn不会随不同种类账户而变化
    //可留在Account类中。
    //2.i当需要使用源类的特性时,有4种选择:
    //(1)将这个特性也移到目标类
    //(2)建立或使用一个从目标类到源类的引用关系。
    //(3)将源对象当作参数传给目标函数
    //(4)如果所需特性是个变量,将它当作参数传给目标函数。
    
    //重构后
    class Account...
    {
    public:
        //该函数可以用委托方式来代替,也可以删除(但必须同时修改所有对该函数的引用点)
        double overdraftCharge()
        {
            return _type.overdraftCharge(_daysOverdrawn); //委托方式
        }
    };
    
    class AccoutType...
    {
    public:
        //使用到源函数中的特性daysOverdrawn,这里将其作为参数传递给目标函数。
        double overdraftCharge(int daysOverdrawn)
        {
            if(isPremium())
            {
                double result = 10;
                if(daysOverdrawn > 7)
                    result += (daysOverdrawn - 7) * 0.85;
                
                return result;
            }
            else
            {
                return daysOverdrawn * 1.75;
            }         
        }
    };

    2. 搬移字段(Move Field)

    2.1 动机

    (1)某个字段被其所驻类之外的另一个类更多地使用到,可以在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。上述所谓“使用”可以是通过get/setter函数间接进行的。

    (2)使用Extract Class时,也可能需要搬移字段,此时可以先搬移字段,然后再搬移函数。

    2.2 做法

    (1)如果字段的访问级是public,使用Encapsulate Field将它封装起来。

    (2)在目标类中建立与源字段相同的字段,并同时建立相应的设值/取值函数。

    (3)决定如何在源对象中引用目标对象。在源类中建一个字段来保存目标对象。

    (4)删除源字段,将所有对源字段的引用替换为某个目标函数的调用。

    2.3 范例

    //搬移字段
    //重构前
    class Account...
    {
    private:
        AccountType _type;
        double _interestRate; //要搬移的字段
        
    public:
        //引用了_interestRate字段的函数
        double interestForAmount_days(double amount, int days)
        {
            return _interestRate * amount * days / 365;
        }
    };
    
    //重构后
    class Account...
    {
    private:
        AccountType _type;
        double _interestRate; //如果有多个函数引用了该字段可以用
                              //Self-Encapsulation封装起来
        //对_interestRate进行封装
        void setInterestRate(double arg)
        {
            _type.setInterestRate(arg);
        }
        
        double getInterestRate(arg)
        {
            return _type.getInterestRate();
        }
                              
    public:  
        //引用了_interestRate字段的函数,使用getInterestRate替代
        double interestForAmount_days(double amount, int days)
        {
            return getInterestRate * amount * days / 365;
        }  
    };
    
    class AccoutType...
    {
    private:
        double _interestRate;
        
    public:
        //新建设值/取值函数
        void setInterestRate(double arg)
        {
            _interestRate = arg;
        }
        
        double getInterestRate()
        {
            return _interestRate;
        }
    };
  • 相关阅读:
    DOMContentLoaded
    闭包之外的解决方法
    前端单页面应用路由
    zepto的tap事件点透问题
    微服务实践指南☞Kong网关的简介和安装
    Visual studio docker build no such file or directory
    Saas物联网共享平台实战
    dotnetty源码解读一些要点
    Ubuntu 安装 JDK 7 / JDK8 的两种方式
    spring入门笔记-(一)、spring boot HelloWorld
  • 原文地址:https://www.cnblogs.com/5iedu/p/5964741.html
Copyright © 2020-2023  润新知