- 1 Extract Method (提炼函数)
- 2 Inline Method (内联函数)
- 3 Inline Temp (内联临时变量)
- 4 Replace Temp with Query (以查询取代临时变量)
- 5 Introduce Explaining Variable (引入解释性变量)
- 6 Split Temporary Variable (分解临时变量)
- 7 Remove Assignments to Parameters (移除对参数的赋值)
- 8 Replace Method with Method Object (以函数对象取代函数)
- 9 Substitute Algorithm (替换算法)
1 Extract Method (提炼函数)
你有一段代码可以被组织在一起并独立出来。
将这段代码放到一个独立的函数中, 并让函数名称解释该函数的用途。
动机
- 过长函数或者需要注释才能让人理解的代码
- 简短而命名良好的函数,有以下优点:
- 函数粒度小,复用机会变大。
- 使得高层函数读起来像一系列注释 。
- 覆写容易。
做法
- 函数名以"做什么",而不是"怎么做"命名。
- 处理局部变量
- 可用查询消除部分局部变量
- 可将局部变量当作参数传给目标函数
- 可返回局部变量
- 如需返回多个,则继续提炼,知道只需返回一个
2 Inline Method (内联函数)
一个函数的本体与名称同样清楚易懂。
在函数调用点插入函数本体,然后移除函数
动机
- 函数内容与名称同样清晰
- 对于提取函数过度的情况,可将不合理的函数内联到一个大型函数中,然后可适当重新提取函数
做法
- 检查函数,确定它不具有多态性
- 如果内联的函数过于复杂,就不要动
3 Inline Temp (内联临时变量)
一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法。
将所有对该变量的引用动作,替换为对它赋值的那个表达式自身
动机
- 你发现某个临时变量被赋予某个函数调用的返回值。
做法
- 确保赋值表达式没有副作用
- 将变量声明为 final,检查该临时变量是否真的只被赋值一次
- 如果对临时变量赋值的表达式计算量较大,可适当不进行此手法
4 Replace Temp with Query (以查询取代临时变量)
你的程序以一个临时变量来保存一个表达式的运算结果。
将整个表达式提炼到一个独立的函数中。将这个变量的引用点替换为对这个新函数的调用。此后,新函数可被其它函数调用。
动机
- 此手法可有效除去临时变量
做法
- 找出只被赋值一次的临时变量。如被赋值多次,分割为多个变量
- 将变量声明为 final,检查该临时变量是否真的只被赋值一次
- 将复制语句提炼到独立函数
5 Introduce Explaining Variable (引入解释性变量)
你有一个复杂的表达式。
将该复杂表达式(或其中一部分)的结果放进一个临时变量,以次变量名称来解释表达式的用途。
动机
- 此手法便于理解代码, 但是引入过多临时变量, 不利于后序Extract Method的使用
- 运用此手法之前可优先尝试Extract Method手法, 相比之下引入解释性变量局限性较大, 当局部变量过多难以进行Extract Method时, 可使用此手法.
做法
- 声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果复制给它。
- 替换
6 Split Temporary Variable (分解临时变量)
某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。
针对每次赋值, 创造一个独立、对应的临时变量。
动机
- 解决变量被多次赋值,意义不明确的问题
做法
- 在第二次赋值处,重新声明临时变量
7 Remove Assignments to Parameters (移除对参数的赋值)
代码对一个参数进行赋值。
以一个临时变量来取代改参数的位置。
动机
- 对参数赋值降低函数清晰度,混用了按值传递和按引用传递这个两种方式。
- 在按值传递的情况下,对参数的任何修改,都不会对调用端造成影响。
做法
- 如果代码的语义是按引用传递,请在调用端检查调用后是否还使用了这个参数,也要检查有多少个按引用传递的参数被赋值后又被调用。请尽量只以return方式返回一个值。如果需要返回的值不止一个,看看可否封装为一个对象,或者为每个返回值设计对应的一个独立函数。
- 如有必要,请用final修饰参数,让编译期检查函数中是否有对参数赋值的情况。
8 Replace Method with Method Object (以函数对象取代函数)
你有一个大型函数, 其中对局部变量的使用使你无法采用Extract Method。
将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后你可以在同一个对象中将这个大型函数分解为多个小型函数。
动机
- 局部变量的存在会增加函数分解难度。如果查询代替局部变量不好使,就使用函数对象。
做法
- 建立一个新类,根据待处理函数的用途,为这个类命名
- 在新类中建立一个final字段,用以保存原先大型函数所在的对象(源对象)。同时,针对原函数的每个临时变量和每个参数,在新类中建立一个对应的字段保存之
- 在新类中建立一个构造函数,接收源对象及原函数的所有参数作为参数
- 在新类中建立一个compute()函数.
- 将原函数的代码复制到compute()函数中。如果需要调用源对象的任何函数,请通过源对象字段调用
- 编译.
- 将旧函数的函数本体替换为这样一条语句:“创建上述新类的一个新对象,而后调用其中的compute()函数”
由于所有局部变量都变成了字段,可以任意分解这个大型函数,不用传递任何参数。
9 Substitute Algorithm (替换算法)
要把某个算法替换为另一个更清晰的算法。
将函数本体替换为另一个算法。
动机
- 在替换之前先保证自己是否充分了解被替换的算法,若算法过大,先行拆解,增加清晰度。
做法
- 替换后要测试