浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第2章 重新组织函数(4):函数对象、替换算法

Posted on 2016-10-11 09:25  浅墨浓香  阅读(422)  评论(0编辑  收藏  举报

8. 以函数对象取代函数(Replace Method with Method Object)

8.1 动机

(1)将一个大型的函数放进一个单独对象中,使局部变量变成对象内的字段,然后可以在同一个对象中将这个大型函数分解为多个小型函数。

(2)局部变量的存在会增加函数分解的难度。如果局部变量太多,可以难以使用Replace Temp with Query来处理,这时可以用函数对象来取代

8.2 做法

(1)建立一个新类,根据待处理函数的用途,为这个类命名。

(2)在新类中建一个const字段,用以保存原先大函数所在的对象。我们将这个字段称为“源对象”。同时,针对原函数的每个临时变量和每个参数在新类中建立一个对应的字段保存之

(3)在新类中建立一个构造函数,接收源对象及原函数的所有参数作为参数。

(4)在新类中建立一个compute()函数。

(5)将原函数的代码复制到compute()函数中。如果需要调用源对象的任何函数,请通过源对象字段调用。

(6)将旧函数的函数本体替换为这样一条语句:“创建上述新类的一个新对象,而后调用其中的compute函数”。

8.3 范例

//以函数对象取代函数
//重构前
class Account
{
public:
    //以下函数没有实例意义,用了演示使用过多的局部变量
    int gamma(int inputVal, int quantity, int yearTodate)
    {
        int importantValue1 = (inputVal * quantity) + delta();
        int importantValue2 = (inputVal * yearToDate) + 100;
        if ((yearToDate - importantValue1) > 100)
            importantValue2 -= 20;
        
        int importantValue3 = importantValue2 * 7;
        //and so on
        return importantvalue3 - 2 * importantValue1;
    }    
};

//重构后
//1.声明一个新类,提供一个const字段用以保存源对象;
//2.函数的每一个参数和每一个临时变量分别以一个字段保存
//3. 加入一个构造函数
class Gamma
{
private:
    const Account* _account;
    int inputVal;
    int quantity;
    int yearToDate;
    int importantValue1;
    int importantValue2;
    int importantValue3;
    
public:
    Gamma(Account* src,int inputVal, int quantity, int yearToDate):_account(src)
    {
        this->inputVal = inputVal;
        this->quantity = quantity;
        this->yearToDate = yearToDate;
    }
    
    int compute()
    {
        int importantValue1 = (inputVal * quantity) + _account->delta();//调用源对象的delta()
        int importantValue2 = (inputVal * yearToDate) + 100;
        if ((yearToDate - importantValue1) > 100)
            importantValue2 -= 20;
        
        int importantValue3 = importantValue2 * 7;
        //and so on
        return importantvalue3 - 2 * importantValue1;        
    } 
};

//修改Account类中的旧函数
int gamma(int inputVal, int quantity, int yearToDate)
{
    Gamma gm(this, inputVal, quantity, yearToDate);
    return gm.compute();
}

9. 替换算法(Substitute Algorithm)

9.1 动机

(1)将函数本体替换为另一个算法

(2)如果一件事可以有更清晰的方式来取代复杂的方式,则可以用此法重构。

(3)使用这项重构手法前,要先确定已经尽可能将函数分解为简单的小型函数,然后才能进行算法的替换工作。

9.2 做法

(1)准备好另一个(替换用的)算法,让它通过编译。

(2)针对现有测试,执行上述的新算法。如果结果与原本结果相同,重构结束

(3)如果测试结果不同于原先,在测试和调试过程中,以旧算法为比较参照标准。

9.3 范例

//替换算法(Java代码)
//重构前
String foundPerson(String[] people)
{
    for(int i = 0; i < people.length; i++)
    {
        if(people[i].equals("Don"))
            return "Don";
        
        if(people[i].equals("John"))     
            return "John";
        
        if(people[i].equals("Kent"))
            return "Kent";   
    }
}
//重构后
String foundPerson(String[] people)
{
    List candiates = Arrays.asList(new String[]{"Don","John","Kent"});
    for(int i = 0; i < people.length; i++)
    {
        if (candiates.contains(people[i]))
            return people[i];
    }
    
    return "";
}