第六章、重新组织函数
1、Extract Method(提炼函数)
——将代码段放在一个独立的函数中,并让函数名称来解释该函数的用途
动机:
将过长的代码或者一段需要注释才能让人理解的代码放在独立函数中
函数的粒度小利于复用;且高层函数读起来像是注释一样
只有良好的命名才能起作用。
函数名的长度不是问题,关键在于函数名称和函数本体之间的语义距离
做法:
创造一个新函数,根据此函数要做什么来命名(根据“做什么”而不是“怎么做”)
将提炼出来的代码复制到新建的目标函数中
检查提炼出的函数的变量完成参数传递
编译测试
2、Inline Method(内联函数)
——在函数调用点插入函数本体,然后移除该函数
动机:
某些函数内部的代码可能和函数名同样清晰易读
有一群组织不合的函数先Inline Method到大型函数中在执行Extract Method
某些函数仅仅是简单的委托,找到这些有用的间接层,去除无用的间接层、
做法:
检查函数,确认其没有多态性(子类由复写的函数)
找到此函数的所有调用点替换为函数本体
编译测试
3、Inline Temp(内联临时变量)
——将所有对该变量的引用动作,替换为对他赋值的表达式本身
动机:
妨碍了其他重构手法
做法:
将临时变量设为fianl检验是否只被赋值一次
找到临时变量的引用点替换为表达式
编译测试
4、Replace Temp with Query(已查询代替临时变量)
——将表达式提炼到独立的函数中将这个临时变量的所有引用点替换为对新函数的调用。
此后,新函数就可以被其他函数使用
动机:
临时变量是暂时的只能在所属函数内部使用,替换为一个查询后所有函数将可以共享
做法:
找到只被赋值一次的临时变量
将该临时变量声明为final
编译
将赋值语句右侧提炼到一个独立的函数中去
编译测试
执行Inline Temp
5、Introduce Explaining Variabe(引入解释性变量)
——将复杂表达式(或将其中的一部分)的结果放在一个临时变量,以此变量名来解释表达式的用途
动机:
表达式可能非常复杂且难以理解
做法:
声明一个final的临时变量,将待分解的复杂表达式的一部分动作的结果赋值给它
将表达式中的部分用临时变量替换
编译测试
6、Split Temporary Variable(分解临时变量)
——针对每次赋值,创造一个独立的、对应的临时变量
动机:
如果临时变量、被赋值超过1次那么其在函数中就承担了一个以上的职责;
如果一个临时变量承担了一个以上的责任他就应该被替换为多个临时变量
不要对结果收集变量不要执行(如i=i+某表达式)
做法:
在带分解的临时变量的声明机器第一次赋值出,修改其名称
将新的临时变量声明为final
以该变量的第二次赋值动作未接,修改此前对该临时变量的所有引用点点,让他们引用新的临时变量
在第二次赋值处,重新声明原先那个临时变量
编译测试
重复上述过程
7、Remove Assignments to Parameters(移除对参数的赋值)
——以一个临时变量取代该参数的位置
动机:
按值传递的条件下,不会对调用方产生影响,让人疑惑
使用出参数的情况下不用使用
做法:
建立一个临时变量,把待处理的参数值赋予它
修改以下的所有引用
编译测试
注意:
final修饰的参数不能改变其值(值类型不能改变值,引用类型不能改变其引用的对象但是可以修改对象的内部值)
8、Replace Method with Method Object(以函数对象取代函数)
——把这个函数放到一个单独对象中,如此一来局部变量将成了对象内的字段,然后就可以在同一个对象中将这个大函数分解成多个小形函数
动机:
只要将相对独立的代码从大型函数中提炼出来,就可以大大提高代码可读性
局部变量会增加函数分解的难度,当很难分解时考虑使用此方法
将局部变量变为成员变量,那么就可以使用Extract Method拆分函数
做法:
建立一个新的类,根据这个函数的用途,为这个类命名
在新的类中建立一个final字段保存该大型函数所在的对象。同时针对原函数的每个局部变量和参数在类中建立对应的字段保存
在新类中建立一个构造函数,接收原对象及原函数所有参数作为参数
在新类中建立一个compute()的函数
将原函数代码复制到compute()中,如果需要调用源对象的任何函数,即可通过新类中的源对象字段调用
编译
将旧函数的函数本体替换为创建一个新类的对象;调用该对象的compute()函数;
9、Substitute Algorithm(替换算法)
——将函数本体替换为另一算法
动机:
如果发现做一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂的方式
在使用之前,尽可能的分解原函数
做法:
准备好另一算法,并保证可以编译通过
针对现有测试,执行上述新算法,如果结果与原来结果相同,完成
如果测试结果不同于原先,以原函数为准测试调试
1、Extract Method(提炼函数)
——将代码段放在一个独立的函数中,并让函数名称来解释该函数的用途
动机:
将过长的代码或者一段需要注释才能让人理解的代码放在独立函数中
函数的粒度小利于复用;且高层函数读起来像是注释一样
只有良好的命名才能起作用。
函数名的长度不是问题,关键在于函数名称和函数本体之间的语义距离
做法:
创造一个新函数,根据此函数要做什么来命名(根据“做什么”而不是“怎么做”)
将提炼出来的代码复制到新建的目标函数中
检查提炼出的函数的变量完成参数传递
编译测试
2、Inline Method(内联函数)
——在函数调用点插入函数本体,然后移除该函数
动机:
某些函数内部的代码可能和函数名同样清晰易读
有一群组织不合的函数先Inline Method到大型函数中在执行Extract Method
某些函数仅仅是简单的委托,找到这些有用的间接层,去除无用的间接层、
做法:
检查函数,确认其没有多态性(子类由复写的函数)
找到此函数的所有调用点替换为函数本体
编译测试
3、Inline Temp(内联临时变量)
——将所有对该变量的引用动作,替换为对他赋值的表达式本身
动机:
妨碍了其他重构手法
做法:
将临时变量设为fianl检验是否只被赋值一次
找到临时变量的引用点替换为表达式
编译测试
4、Replace Temp with Query(已查询代替临时变量)
——将表达式提炼到独立的函数中将这个临时变量的所有引用点替换为对新函数的调用。
此后,新函数就可以被其他函数使用
动机:
临时变量是暂时的只能在所属函数内部使用,替换为一个查询后所有函数将可以共享
做法:
找到只被赋值一次的临时变量
将该临时变量声明为final
编译
将赋值语句右侧提炼到一个独立的函数中去
编译测试
执行Inline Temp
5、Introduce Explaining Variabe(引入解释性变量)
——将复杂表达式(或将其中的一部分)的结果放在一个临时变量,以此变量名来解释表达式的用途
动机:
表达式可能非常复杂且难以理解
做法:
声明一个final的临时变量,将待分解的复杂表达式的一部分动作的结果赋值给它
将表达式中的部分用临时变量替换
编译测试
6、Split Temporary Variable(分解临时变量)
——针对每次赋值,创造一个独立的、对应的临时变量
动机:
如果临时变量、被赋值超过1次那么其在函数中就承担了一个以上的职责;
如果一个临时变量承担了一个以上的责任他就应该被替换为多个临时变量
不要对结果收集变量不要执行(如i=i+某表达式)
做法:
在带分解的临时变量的声明机器第一次赋值出,修改其名称
将新的临时变量声明为final
以该变量的第二次赋值动作未接,修改此前对该临时变量的所有引用点点,让他们引用新的临时变量
在第二次赋值处,重新声明原先那个临时变量
编译测试
重复上述过程
7、Remove Assignments to Parameters(移除对参数的赋值)
——以一个临时变量取代该参数的位置
动机:
按值传递的条件下,不会对调用方产生影响,让人疑惑
使用出参数的情况下不用使用
做法:
建立一个临时变量,把待处理的参数值赋予它
修改以下的所有引用
编译测试
注意:
final修饰的参数不能改变其值(值类型不能改变值,引用类型不能改变其引用的对象但是可以修改对象的内部值)
8、Replace Method with Method Object(以函数对象取代函数)
——把这个函数放到一个单独对象中,如此一来局部变量将成了对象内的字段,然后就可以在同一个对象中将这个大函数分解成多个小形函数
动机:
只要将相对独立的代码从大型函数中提炼出来,就可以大大提高代码可读性
局部变量会增加函数分解的难度,当很难分解时考虑使用此方法
将局部变量变为成员变量,那么就可以使用Extract Method拆分函数
做法:
建立一个新的类,根据这个函数的用途,为这个类命名
在新的类中建立一个final字段保存该大型函数所在的对象。同时针对原函数的每个局部变量和参数在类中建立对应的字段保存
在新类中建立一个构造函数,接收原对象及原函数所有参数作为参数
在新类中建立一个compute()的函数
将原函数代码复制到compute()中,如果需要调用源对象的任何函数,即可通过新类中的源对象字段调用
编译
将旧函数的函数本体替换为创建一个新类的对象;调用该对象的compute()函数;
9、Substitute Algorithm(替换算法)
——将函数本体替换为另一算法
动机:
如果发现做一件事可以有更清晰的方式,就应该以较清晰的方式取代复杂的方式
在使用之前,尽可能的分解原函数
做法:
准备好另一算法,并保证可以编译通过
针对现有测试,执行上述新算法,如果结果与原来结果相同,完成
如果测试结果不同于原先,以原函数为准测试调试