重新组织函数是《重构》一书中与函数相关的核心重构手法,目的是让代码更易读、更易维护。

1. Extract Method(提炼函数)

当一个函数过长,或者需要注释才能让人理解某段代码的用途时,应当把该段代码提炼到一个独立的函数里,并根据其意图为新函数命名。

做法:

  1. 创造一个新函数,根据这个函数的意图来命名。
  2. 把提炼出来的代码拷贝到新函数里面。
  3. 仔细检查提炼出来的代码,看看其中是否引用了"作用域限于原函数"的变量,包括局部变量和原函数参数。
  4. 检查是否有仅作用于被提炼代码段的临时变量,如果有,在目标函数中将其声明为临时变量。
  5. 把被提炼代码中需要读取的临时变量,当做参数传给目标函数。
  6. 在原函数中,用对目标函数的调用替换被提炼出来的代码段。
  7. 检查被提炼代码段是否有局部变量被修改了。如果有,看看是否可以处理为一个查询;如果不能,则不能原封不动地提炼,需先参考 Split Temporary Variable 进行拆分,或用 Replace Temp With Query 消灭临时变量,再提炼。

2. Inline Method(内联函数)

当一个函数没有必要作为独立函数存在,或者委托层级过多时,可以将其内联回调用处。

做法:

  1. 确认该函数不具备多态性,找出所有调用者,将函数调用替换为内联代码。

3. Inline Temp(内联临时变量)

有些临时变量是多余的,可以直接删掉,将其引用处替换为对应的表达式。

4. Replace Temp With Query(用查询替代临时变量)

当程序用一个临时变量来保存某一表达式的结果时,可以把这个表达式提炼到一个独立的函数中,再将所有对该临时变量的引用替换为对新函数的调用。这样新函数就可以被其他地方复用。临时变量的问题在于它只在当前函数内可见,容易驱使你写出更长的函数;改为查询之后,可读性和复用性都会好得多。

做法:找出只被赋值一次的临时变量(C++ 可用 const 来确认),然后提炼出函数,再用 Inline Temp 处理原来的临时变量。

5. Introduce Explaining Variable(引入解释性变量)

当表达式过于复杂时,可以把复杂表达式或其中一部分的结果存入一个临时变量,用变量名来解释表达式的用途,从而提升可读性。

6. Split Temporary Variable(分解临时变量)

如果某个临时变量被赋值超过一次,且它既不是循环变量,也不用于累积计算结果,那么应该针对每次赋值创建一个独立的临时变量,确保每个临时变量只承担一项职责。

7. Remove Assignments to Parameters(移除对参数的赋值)

不要对函数参数直接赋值,注意区分传值和传地址(引用)的语义差异。

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

如果一个大型函数由于局部变量过多而无法直接使用 Extract Method,可以把这个函数放进一个单独的对象中。这样局部变量就成了对象的字段,之后便可以在这个类中对大型函数进行进一步拆分。

9. Substitute Algorithm(替换算法)

如果函数内部的算法可以用更清晰的方式实现,就应当替换。例如,函数中大量的 if 判断如果可以用查询或循环来替代,那就替换掉。