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

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 "";
}
时间: 2024-07-28 20:25:29

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

重构改善既有代码的设计--第6章--重新组织函数

第6章 重新组织函数 6.1 Extract Method Long methods,因为包含太多信息和逻辑,不容易处理和修改.所以需要进行Extract Method. (1)场景 当一个函数过长,或者一段代码需要注释才能看懂,就可以考虑将其放入独立函数中. (2)优点 每个函数粒度小,被复用的几率大,被修改的难度也会低一些:高层函数逻辑分明. (3)做法 以"做什么"命名,而不是"怎么做".比如,printDetail(). 将源函数中的某一段提取到目标函数中.

第2章 重新组织函数(3):引入解释性变量、分解临时变量和移除对参数的赋值

5. 引入解释性变量(Introduct Explaining Variable) //引入解释性变量 //重构前 if((platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize > 0) { //do somethin

【转】PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数

原文地址: PHP 杂谈<重构-改善既有代码的设计>之一 重新组织你的函数 思维导图 点击下图,可以看大图. 介绍 我把我比较喜欢的和比较关注的地方写下来和大家分享.上次我写了篇<php 跟老大的对话>.还是有很多疑问,这书帮了我不少的忙. 如果你比较繁忙,或者懒得看文字,建议你直接看截图,也会有很大的收获的.你可以通过比较截图中的代码就能知道孰优孰劣了. 代码部分我为什么用图呢?因为我经常用手机看代码,博客园的代码在手机里乱七八糟的,还是看图比较舒服. 专业术语 我们毕竟是用英文

《Flash ActionScript 3 殿堂之路》二,三,四章 运算符,语句,函数

1. 运算符相关 1 var a:int = 5; 2 var b:uint = 5; 3 trace(a === b);//输出true.全等运算符对于数值类型一视同仁, 4 //如果int,uint和Number类型数值相同,全等运算 2. 1 //注意:等于和全等运算符对于变量的默认值的比较是不同的 2 var a:Number; 3 var b:Number; 4 trace(a); 5 trace(b); 6 trace(a == b); 7 trace(a === b); 8 //输

萌新向Python数据分析及数据挖掘 第一章 Python基础 第八节 函数

第一章 Python基础 第八节 函数 定义函数 函数 其实就可以理解为外挂,把一些常用的.重复率比较多你又不想重复写的东西写进函数,加上开关实现简化操作 举个简单的例子 1 def greet_user(username): 2 #定义一个叫做"迎接用户"的外挂,让他能直接打印一个问候语,括号里面是函数需要输入的东西,也就是个性化的东西 3 """先是简单的问候语""" 4 print("Hello! "

《python解释器源码剖析》第12章--python虚拟机中的函数机制

12.0 序 函数是任何一门编程语言都具备的基本元素,它可以将多个动作组合起来,一个函数代表了一系列的动作.当然在调用函数时,会干什么来着.对,要在运行时栈中创建栈帧,用于函数的执行. 在python中,PyFrameObject对象就是一个对栈帧的模拟,所以我们即将也会看到,python虚拟机在执行函数调用时会动态地创建新的PyFrameObject对象.随着函数调用链的增长,这些PyFrameObject对象之间也会形成一条PyFrameObject对象链,这条链就是对象x86平台上运行时栈

Visual LISP 第2章 数据类型、表达式和函数(5)函数

1.定义AutoLISP函数 (defun 函数名(变元……/局部变量……)表达式) (1)函数名与变量名的命名规则相同,不应与现有AutoLISP函数重名,否则,现有函数将被新定义的功能所取代.(2)变元即参数.即便没有变元也不能省略"()".(3)局部变量.这里的局部变量是指局限于该函数内部所用的变量,只在该函数调用期间得到定义,调用结束,局部变量的值均为nil,同事释放所占存储空间.如不声明,它们则将成为全局变量.局部变量的声明不仅可以节省存储空间,还可以避免函数之间相互干扰.局

第三章 Python基础——文件操作&amp;函数 续

3.6函数进阶 名称空间:name space 例:若变量X=1,1存放于内存中,那存放X与1绑定关系的地方就叫做名称空间. 名称空间共三种,分别如下: locals:是函数内名称空间,包括局部变量和形参 globals:全局变量,函数定义所在模块的名字空间 builtins:内置模块的名字空间 不同变量的作用域不同就是由于这个变量所在的命名空间决定的. 作用域即范围: 全局范围:全局存活,全局有效 局部范围:临时存活,局部有效 注:查看作用域方法 globals(),locals() 作用域查

js中的函数,Date对象,Math对象和数组对象

函数就是完成某个功能的一组语句,js中的函数由关键字 function + 函数名 + 一组参数定义;函数在定义后可以被重复调用,通常将常用的功能写成一个函数,利用函数可以使代码的组织结构更多清晰. 其语法结构为 function funName (arg0, arg1, … argN){        //statements    } function say_hello (name, msg){ alert(“hello”+ name + “:”+ msg); } say_hello(“d