第3章 在对象之间搬移特性:提炼类类的内联化

Posted 浅墨浓香

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第3章 在对象之间搬移特性:提炼类类的内联化相关的知识,希望对你有一定的参考价值。

3. 提炼类(Extract Class)

3.1 动机

(1)某个类做了应该由两个类做的事,可以将相关字段和函数从旧类搬移到新类

(2)当某些特性需要以一种方式来子类化,另外一些特性则需要以另一种方式子类化,这就意味着需要分解原来的类。

3.2 做法

(1)决定如何分解类所负的责任。

(2)建立一个新类,用以表现从旧类中分离出来的责任。如果旧剩下的责任与旧类名称不符,也可以为旧类更名。

(3)建立“从旧类访问新类”的连接关系。有时可能需要一个双向连接,但是在真正需要它之前,不要建新“从新类通往旧类”的连接。

(4)对于要搬移的每一个字段,运用Move Field方法进行搬移

(5)使用Move Method将必要的函数搬移到新类。先搬移较低层函数(也就是“被其他函数调用”多于“调用其他函数”者),再搬移较高层函数

(6)检查,精简每个类的接口。决定是否公开新类

3.3 范例

//提炼类(Extract Class)
//重构前(人与电话号码可以分成两个类)
class Person...
{
private:
    string _name;
    string _officeAreaCode;
    string _officeNumber;
public:
    string getName(){return _name;}
    
    string getTelephoneNumber()
    {
        return "(" + _officeAreaCode + ") " + _officeNumber; 
    } 
    
    string getOfficeAreaCode(){return _officeAreaCode;}
    void setOfficeAreaCode(string arg){_officeAreaCode = arg;}

    string getOfficeNumber(){return _officeNumber;}
    void setOfficeNumber(string arg){officeNumber = arg;}    
};

//重构后
class TelephoneNumber
{
private:
    //Move Field将areaCode和number字段移动过来
    //并同时建立相应的设值/取值函数。
    string _areaCode;
    string _number;
public:
    string getAreaCode(){return _areaCode;}
    void setAreaCode(string arg){_areaCode = arg;}
    
    string getNumber(){return _number;}
    void setNumber(string arg){_number = arg;}
    
    //使用Move Method方法将getTelephoneNumber移动过来
    string getTelephoneNumber()
    {
         return "(" + _areaCode + ") " + _number;
    } 
};

class Person
{
private:
    //建立从Person到TelephoneNumber的连接
    TelephoneNumber _officeTelephone;
    
    //更改被移动字段的取值和设值函数
    string getOfficeAreaCode()
    {
        _officeTelphone.getAreaCod();
    }
    void setOfficeAreaCode(string arg)
    {
        _officeTelephone.setAreaCode(arg);
    }
public:
    string getName(){return _name;}
    
    string getTelephoneNumber()
    {
        _officeTelephone.getTelephoneNumber();        
    } 
    
    //公开新类(也可以将Person中与电话号码相关的函数
    //委托至TelphoneNumber,从而完全隐藏这个新类)
    TelephoneNumber& getOfficeTelephone()
    {
        return _officeTelephone;
    }
};

4. 将类内联化(Inline Class)

4.1 动机

(1)如果某个类没有做太多的事情,可以将这个类的所有特性搬移到另一个类中,然后移除原类,即合并为一个类。

(2)Inline Class和Extract Class正好相反。如果一个 类不再承担足够责任、不再有理由单独存在。这可将这个类的内联到使用这个类的用户(也是个类)中去。

4.2 做法

(1)在目标类身上声明源类的public接口,并将其中所有函数委托至源类(暂时的做法,主要是用于测试)。如果 “以一个独立接口表示源函数”更合适的话,就应该在内联之前先使用Extract Interface。

(2)修改所有源类引用点,改而引用目标类

(3)运用Move Method和Move Field将源类的特性全部搬移到目标类

(4)删除源类。

4.3 范例

//将类内联化(Inline Class):将上例的Telephone放回到Person类中去
//重构前
class TelephoneNumber
{
private:
    //Move Field将areaCode和number字段移动过来
    //并同时建立相应的设值/取值函数。
    string _areaCode;
    string _number;
public:
    string getAreaCode(){return _areaCode;}
    void setAreaCode(string arg){_areaCode = arg;}
    
    string getNumber(){return _number;}
    void setNumber(string arg){_number = arg;}
    
    //使用Move Method方法将getTelephoneNumber移动过来
    string getTelephoneNumber()
    {
         return "(" + _areaCode + ") " + _number;
    } 
};

class Person
{
private:
    //建立从Person到TelephoneNumber的连接
    TelephoneNumber _officeTelephone;
    
    //更改被移动字段的取值和设值函数
    string getOfficeAreaCode()
    {
        _officeTelphone.getAreaCod();
    }
    void setOfficeAreaCode(string arg)
    {
        _officeTelephone.setAreaCode(arg);
    }
public:
    string getName(){return _name;}
    
    string getTelephoneNumber()
    {
        _officeTelephone.getTelephoneNumber();        
    } 
    
    //公开新类(也可以将Person中与电话号码相关的函数
    //委托至TelphoneNumber,从而完全隐藏这个新类)
    TelephoneNumber& getOfficeTelephone()
    {
        return _officeTelephone;
    }
};

//重构中
//1.将Peson中声明TelephoneNumber中所有public函数
//2.找出Telephone的所有用户,让它们转而使用Person的接口
//  如:Person martin;
//      martin.getOfficeTelephone().setAreaCode("781");
//  变为:martin.setAreaCode("781");
//3. 反复利用Move Method和Move Field,直到TelephoneNumber不复存在

//重构后:
class Person...
{
private:
    string _name;
    string _officeAreaCode;
    string _officeNumber;
public:
    string getName(){return _name;}
    
    string getTelephoneNumber()
    {
        return "(" + _officeAreaCode + ") " + _officeNumber; 
    } 
    
    string getOfficeAreaCode(){return _officeAreaCode;}
    void setOfficeAreaCode(string arg){_officeAreaCode = arg;}

    string getOfficeNumber(){return _officeNumber;}
    void setOfficeNumber(string arg){officeNumber = arg;}    
};

以上是关于第3章 在对象之间搬移特性:提炼类类的内联化的主要内容,如果未能解决你的问题,请参考以下文章

3在对象之间搬移特性

重构.改善既有代码的设计7在对象之间搬移特性(如何优化类)