重构—改善既有代码的设计007:在对象之间搬移特性(Moving Features Between Objects)

来源:互联网 发布:深圳110网络报警平台 编辑:程序博客网 时间:2024/06/14 07:40

重构—改善既有代码的设计007:在对象之间搬移特性(Moving Features Between Objects)

一:MOVE MOTHOD
二:MOVE FIELD
三:EXTRACT CLASS
四:INLINE CLASS
五:HIDE DELEGATE
六:REMOVE MIDDLE MAN
七:INTRODUCE FOREIGN METHOD
八:INTRODUCE LOCAL METHOD

一:MOVE MOTHOD
    你的程序中,有个函数一起所驻类之外的另一个类进行更多的交流:即调用后者或被后者调用
    1:动机
        MOVE METHOD作为重构理论的支柱,如果一个类有太多的行为,或如果一个类与另一个类有太多合作而形成高度耦合,就可用此方法。
        利用此方法可以是系统中的类更简单,这些类最终也将更干净利落的实现系统交付的任务。
    2:做法
        .检查源类定义的源函数所有用的一切特性,考虑他们是否也该被搬移。
        .检查源类的子类和超类,看看是否有函数的其他声明
        .在目标类中声明该函数
        .将源方法的代码拷贝到目标方法中,调整后者,时期能在新家中正常运行
        .决定如何从源正确引用目标对象
        .修改源方法,使之成为一个纯委托方法
    3:范例
        class AccountType
        {
        }
        class Account
        {
            private AccountType _type;
            private int _daysOverdrawn;
            double overdraftCharge( )
            {
                if (!_type.isPreminm())
                {
                    double result = -10;
                    if (_daysOverdrawn > 7)
                        result += (_daysOverdrawn - 7) * 0.85;
                    return result;
                }
                else
                    return _daysOverdrawn * 1.75;
            }
            double bankCharge()
            {
                double result = 4.5;
                if (_daysOverdrawn > 0)
                    result += overdraftCharge();
                return result;
            }
        }
        改为:
        class AccountType
        {
            double overdraftCharge(int daysOverdrawn)
            {
                if (!isPreminm())
                {
                    double result = -10;
                    if (daysOverdrawn > 7)
                        result += (daysOverdrawn - 7) * 0.85;
                    return result;
                }
                else
                    return daysOverdrawn * 1.75;
            }
        }
        class Account
        {
            private AccountType _type;
            private int _daysOverdrawn;
            double overdraftCharge( )
            {
                return _type.overdraftCharge(_daysOverdrawn);
            }
            double bankCharge()
            {
                double result = 4.5;
                if (_daysOverdrawn > 0)
                    result += overdraftCharge();
                return result;
            }
        }
        如果删除源函数的话,则可改为
        class AccountType
        {
            double overdraftCharge(int daysOverdrawn)
            {
                if (!isPreminm())
                {
                    double result = -10;
                    if (daysOverdrawn > 7)
                        result += (daysOverdrawn - 7) * 0.85;
                    return result;
                }
                else
                    return daysOverdrawn * 1.75;
            }
        }
        class Account
        {
            private AccountType _type;
            private int _daysOverdrawn;
            double bankCharge()
            {
                double result = 4.5;
                if (_daysOverdrawn > 0)
                    result += _type.overdraftCharge();
                return result;
            }
        }
       当参数多的时候,可以考虑传入对象
        class AccountType
        {
            double overdraftCharge(Account account)
            {
                if (!isPreminm())
                {
                    double result = -10;
                    if (account.getDaysOverdrawn() > 7)
                        result += (account.getDaysOverdrawn() - 7) * 0.85;
                    return result;
                }
                else
                    return account.getDaysOverdrawn() * 1.75;
            }
        }
        class Account
        {
            private AccountType _type;
            private int _daysOverdrawn;
            double bankCharge()
            {
                double result = 4.5;
                if (_daysOverdrawn > 0)
                    result += _type.overdraftCharge();
                return result;
            }
        }

二:MOVE FIELD
    1:你的程序中,某个值域被其所驻类之外的另一个类更多的用到
        在目标类建立一个新的值域,修改源域的所有用户,令他们改用新的值域
    2:动机
        在类之间移动状态和行为,是重构过程中必不可少的措施。
        随着系统发展,你会发现自己需要新的类,并需要将原本工作责任拖到新的类中。
    3:做法
        .如果值域的属性是PUBLIC,首先使用ENCAPSULATE FIELD将它封装起来
        .编译,测试
        .在目标类中建立和源值域相同的值域,并同时建立相应的设值/取值函数
        .编译目标类
        .决定如何在源对象中引用目标对象
        .删除源值域
        .将所有对源值域的引用替换为对目标适当函数的调用
        .编译,测试
    4:范例
        class AccountType
        {
        }
        class Account
        {
            private AccountType _type;
            private int _interestRate;
            double interestForAccount_days(double amount, int days)
            {
                return _interestRate * amount * days / 365;
            }
        }
        改为:
        class AccountType
        {
            private double _interestRate;
            void setInterestRate(double arg)
            {
                _interestRate = arg;
            }
            double getInterestRate()
            {
                return _interestRate;
            }
        }
        class Account
        {
            private AccountType _type;
            double interestForAccount_days(double amount, int days)
            {
                return _type.getInterestRate() * amount * days / 365;
            }
        }

三:EXTRACT CLASS
    1:某个类做了应该由两个类做的事
        建立一个新类,将相关的值域和函数从旧的类搬移到新的类中
    2:动机
        一个类应该是一个清楚地抽象,处理一些明确的责任。
        有些类往往含有大量函数和数据,让人不太容易理解。
    3:做法
        .决定如何分解类所负责任
        .建立一个新类,用以表现从旧类中分离出来的责任
        .建立从旧类访问新类的连接关系
        .对于你想移动的每一个值域,用MOVE FIELD移动
        .每次搬移后,编译,测试
        .使用MOVE METHOD将必要的函数搬移到新类中,先搬移较底层函数,即被其他函数调用多于调用其他函数的,再搬移较高层函数
        .每次搬移之后,编译,测试
        .检查,精简每个类接口
        .决定是否让新类曝光。
    4:范例
        class Person
        {
            private string _name;
            private string _officeAreaCode;
            private string _officeNumber;
            public string getName()
            {
                return _name;
            }
            public string getTelephoneNumber
            {
                return _officeAreaCode + _officeNumber;
            }
            string getOfficeAreaCode()
            {
                return _officeAreaCode;
            }
            string setOfficeAreaCode(string arg)
            {
                _officeAreaCode = arg;
            }           
            string getOfficeNumber()
            {
                return _officeNumber;
            }
            string setOfficeNumber(string arg)
            {
                _officeNumber = arg;
            }
        }
        改为:
        class TelephoneNumber
        { 
            private string _areaCode;
            private string _number;
            public string getTelephoneNumber()
            {
                return _areaCode + _number;
            }
            string getOfficeAreaCode()
            {
                return _areaCode;
            }
            string setOfficeAreaCode(string arg)
            {
                _areaCode = arg;
            }           
            string getOfficeNumber()
            {
                return _number;
            }
            string setOfficeNumber(string arg)
            {
                _number = arg;
            }
        }
        class Person
        {
            private string _name;
            private TelephoneNumber _officeTelephone = new TelephoneNumber();

            public string getName()
            {
                return _name;
            }
            public string getTelephoneNumber()
            {
                return _officeTelephone.getTelephoneNumber();
            }
            TelephoneNumber getOfficeTelephone()
            {
                return _officeTelephone;
            }
        }
       

四:INLINE CLASS
    1:某个类没有做太多的事情,即没有承担足够的责任
        可以将类的所有特性搬移到另一个类中,然后移除原来类
    2:动机
        和EXTRACT CLASS相反。

五:HIDE DELEGATE
    1:可以直接调用其服务对象的代理类
        在服务端某个类建立客户所需的所有函数,用以隐藏委托关系
    2:动机
        封装意味着每个对象都应该尽可能少了解系统的其他部分,如此一来,一旦发生变化,需要了解这一变化的对剑就会比较少。
    3:做法
        .对于每一个委托关系中的函数,在服务端建立一个简单的委托函数
        .调整客户,令它只调用服务提供的函数
        .每次调整后,编译并测试
        .如果将来不再有任何客户需要取用委托类,便可移除服务中的相关访问函数
        .编译,测试
    4:范例
        class Department
        {
            private string _chargeCode;
            private Persion _manager;
            public Department(Person manager)
            {
                _manager = manager;
            }
            public Persion getManager()
            {
                return _manager;
            }
        }
        class Person
        {
            Department _department;
            public Department getDepartment()
            {
                return _department;
            }
            public void setDepartment(Department arg)
            {
                _department = arg;
            }
        }
        改为:
       class Department
        {
            private string _chargeCode;
            private Persion _manager;
            public Department(Person manager)
            {
                _manager = manager;
            }
            public Persion getManager()
            {
                return _manager;
            }
        }
        class Person
        {
            Department _department;
            public Department getDepartment()
            {
                return _department;
            }
            public void setDepartment(Department arg)
            {
                _department = arg;
            }
            public Person getManager()
            {
                return _department.getManager();
            }
        }

六:REMOVE MIDDLE MAN
    1:某个类做了过多简单的委托动作
        让客户直接调用受托类
    2:动机
    3:做法
        .建立一个函数,用以取用受托对象
        .对于每个受托函数,在服务中删除该函数,并将客户对该函数的调用替换为受托对象的调用
        .处理每个受托函数后,编译,测试
    4:范例

七:INTRODUCE FOREIGN METHOD
    DateTime newStart = new DateTime(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDay() - 1);

    DateTime newStart = nextDay(previousEnd);
    private static DateTime nextDay(DateTime arg)
    {
        new DateTime(arg.getYear(), arg.getMonth(), arg.getDay() - 1);
    }

八:INTRODUCE LOCAL METHOD
    建立一个新类,使它包含这些额外函数,让这个扩展品成为源类的子类或外覆类

原创粉丝点击