重构六:重新组织你的函数

228 阅读3分钟

Extract Method(提炼函数)

将长函数或者有统一用途的函数提炼出来,放进一个独立函数中,用函数名解释该函数的用途。

不在于函数行数多少,只要能增加清晰度,就去做

一般情况下分为:无局部变量,有局部变量,局部变量在源函数中有操作。

对局部变量再赋值 ,如:

int a = 1;
int b = a * 1;
===>
int b = getB(a);

每个函数最好只有一个返回值,如果有多个返回值,尝试安排多个函数。

Inline Method(将函数内联化)

  1. 函数内部代码和函数名称同样清晰易读, 在函数调用点直接插入函数本体,然后移除该函数。
  1. 手上有一群不合理的函数,将他们合并到一个大函数中,在进行重构拆分。

Inline Temp (将临时变量内联化)

只有一个临时变量,只是被简单表达式赋值了一次,而妨碍了重构手法,则需要将表达式内联化,去掉临时变量

Replace Temp with Query(以查询取代临时变量)

找到只被赋值一次的临时变量,将等号右侧的赋值语句提取为独立函数。

循环:再循环中出现多个临时表量赋值,每个变量拆分出一个独立函数。这样有一个问题,会造成循环重复执行多次,重构中的建议为:确定是否影响性能,如果影响,再将变量都放回去。

tips:将临时表量设置为final,可确定是否只赋值了一次

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

将复杂表达式用临时变量来表示其用途,类似于Extract Method。

 if ( (platform.toUpperCase().indexOf("MAC") > -1) &&
     (browser.toUpperCase().indexOf("IE") > -1) &&
      wasInitialized() && resize > 0 )
{
     // do something
}

=>

   final boolean isMacOs     = platform.toUpperCase().indexOf("MAC") > -1;
   final boolean isIEBrowser = browser.toUpperCase().indexOf("IE")  > -1;
   final boolean wasResized  = resize > 0;
   if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
       // do something
   }

当使用Extract Method花费大量工作量的时候,再考虑使用引入解释变量,优先使用Extract Method。经过引入解释性变量之后,再尝试使用Extract Method将解释性变量去掉。

Split Temporary Variable (剖解临时变量)

临时变量在后面的逻辑中如果没有累加,字符串拼接,写入stream或想集群添加元素,都应该只被赋值一次,一个临时变量表示一个结果。

对于多次给临时变量赋值的逻辑,如果没有上述操作,则单独定义临时变量。

    double temp = 2 * (_height + _width);
    System.out.println (temp);
    temp = _height * _width;
    System.out.println (temp);

=>

    final double perimeter = 2 * (_height + _width);
    System.out.println (perimeter);
    final double area = _height * _width;
    System.out.println (area);

Remove Assignments to Parameters (移除对参数的赋值动作)

以一个临时变量取代入参参数

   int discount (int inputVal, int quantity, int yearToDate) {
       if (inputVal > 50) inputVal -= 2;

=>

   int discount (int inputVal, int quantity, int yearToDate) {
       int result = inputVal;
       if (inputVal > 50) result -= 2;

注意区别pass by value 和 pass by reference.本质上pass by reference是按值传递的,只不过这个值要理解为整个对象。

Remove Method with Method Object(以函数对象取代函数)

参数过多时,可以构造一个参数对象,将临时变量和局部变量一一对应保存,

在新class中建立一个构造函数,接收元对象及原函数的所有参数作为参数。

再将逻辑移到参数对象中,紧接着对逻辑做重构就会变得相对简单。

Substitute Algorithm(替换你的算法)

将原算法替换成另一个更清晰的算法,直接更换方法体(method body)。

注意点:确保新旧算法的所有test case结果是否一致。