首页 > 代码库 > 读书笔记-重构方法之一:提炼方法(Extract Method)

读书笔记-重构方法之一:提炼方法(Extract Method)

第六章 重新组织你的函数

6.1  Extract Method(提炼方法)

对付过长函数,一般重要的重构方法就是Extract Method,他把一段代码从原先的函数中提取出来,放在单独的函数中。简洁而清晰,短小而精炼。

 

1 void printOwing (douoble amount)2 {3     printBanner();4     //print details5     System.out.println(“name:”+_name);6     System.out.println(“amount”+amount);7 }

 

提炼后:

 1 void printOwing (douoble amount) 2  3 { 4  5     printBanner(); 6  7     printDetails(); 8  9 }10 11 Void printDetails(double amount)12 13 {14 15     System.out.println(“name:”+_name);16 17     System.out.println(“amount”+amount);18 19 }

Extract Method最大的困难就是处理局部变量,所以需要注意一下步奏。

做法:

1、创造一个新的函数,根据这个函数的意图来给他命名(以它[做什么]命名,而不是以它[怎么做]命名)。

2、将提炼出来的代码从源函数(source)拷贝到新建的目标函数(target)中。

3、仔细检查提炼出来的代码,是否引用了[作用域限于源函数]的变量(包括局部变量和源函数参数)。

4、检查是否有[仅用于被提炼代码]的临时变量。如果有,在目标函数中将他们声明为临时变量。

5、检查被提炼码,看看是否有任何局部变量的值被它改变,或者被修改的变量不止一个,就不能原封不动的提炼出来了。

6、将被提炼码中需要读取的局部变量,当做参数传给目标函数。

7、处理完所有的局部变量,在原函数中调用。

实例:

范例一:无局部变量

提炼前:

 1 Void printOwing() 2  3 { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=0.0; 8  9  10 11     //print banner12 13     System.out.println(“*****************************”);14 15     System.out.println(“********Customer Owes********”);16 17     System.out.println(“*****************************”);18 19  20 21     //calculate outstanding22 23     While(e.hasMoreElements())24 25     {26 27     Order each=(Order) e.nextElement();28 29     Outstanding+=each.getAmount();30 31     }32 33  34 35     //print details36 37     System.out.println(“name:”+_name);38 39     System.out.println(“amount”+outstanding);40 41 }
View Code

我们可以轻松的提炼出 print banner 的代码。

 1     Void printOwing() 2      3     { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=0.0; 8  9     print Banner();10 11     //calculate outstanding12 13     While(e.hasMoreElements())14 15     {16 17     Order each=(Order) e.nextElement();18 19     Outstanding+=each.getAmount();20 21     }22 23     //print details24 25     System.out.println(“name:”+_name);26 27     System.out.println(“amount”+outstanding);28 29     }30 31     Void printBanner()32 33     {34 35     //print banner36 37     System.out.println(“*****************************”);38 39     System.out.println(“********Customer Owes********”);40 41     System.out.println(“*****************************”);42 43     }
View Code

范例二:有局部变量

局部变量最简单的情况是:被提炼码只是读取这些变量的值,并不修改它们,这种情况下可以简单地将它们当做参数传给目标函数。

提炼前:

 1     Void printOwing() 2  3     { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=0.0; 8  9     print Banner();10 11     //calculate outstanding12 13     While(e.hasMoreElements())14 15     {16 17     Order each=(Order) e.nextElement();18     19     Outstanding+=each.getAmount();20 21     }22 23     //print details24 25     System.out.println(“name:”+_name);26 27     System.out.println(“amount”+outstanding);28     }
View Code

提炼后:

 1   void printOwing() 2  3     { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=0.0; 8  9     print Banner();10 11     //calculate outstanding12 13     While(e.hasMoreElements())14 15     {16 17     Order each=(Order) e.nextElement();18 19     Outstanding+=each.getAmount();20 21     }22 23     printDetails(outstanding);24 25     }26 27     Void printDetails(double outstanding)28 29     {30 31     System.out.println(“name:”+ _name);32 33     System.out.println(“amount”+ outstanding);34 35     }
View Code

处理多个局部变量也可以使用上述这种方法。

范例三:对局部变量再赋值

如果被提炼码对局部变量赋值,问题就变得复杂了,这里我们只讨论临时变量的问题。

被赋值的临时变量也分为两种情况。比较简单的情况是:这个变量只是在被提炼码中使用,这样,可以将这个临时变量的声明一道被提炼码中,然后一起提炼出去。另一种情况是:被提炼码之外的代码也是用了这个变量。

提炼前:

 1     Void printOwing() 2  3     { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=0.0; 8  9     print Banner();10     11     //calculate outstanding12 13     While(e.hasMoreElements())14     {15 16     Order each=(Order) e.nextElement();17 18     Outstanding+=each.getAmount();19 20     }21 22     printDetails(outstanding);23 24     }
View Code

提炼后:

 1  void printOwing() 2  3     { 4  5     print Banner(); 6  7     Double outstanding=getOutstanding(); 8  9     printDetails(outstanding);10 11     }12 13     Double getOutstanding()14 15     {16 17     Enumeration e=_orders.elements();18 19     Ddouble outstanding=0.0;20 21     While(e.hasMoreElements())22 23     {24 25     Order each=(Order) e.nextElement();26 27     Outstanding+=each.getAmount();28 29     }30     31     Return outstanding();32 33     }
View Code

Enumeration 变量e只是在被提炼码中使用到,所以可以将它整个搬到新函数中。Double 变量 outstanding在被提炼码内外都被用到,所以必须让提炼出来的新喊出返回它。

这个例子中,outstanding变量只是很简单的被初始化为一个明确的值,所以可以只在新函数中对它初始化。如果代码还对这个变量做了其他处理,就必须将它的值作为参数传给目标函数。对于这种变化,最初的代码可能是这样:

 1 Void printOwing(double previousAmount ) 2  3 { 4  5     Enumeration e=_orders.elements(); 6  7     Ddouble outstanding=previousAmount * 1.2; 8  9     print Banner();10 11     //calculate outstanding12 13     While(e.hasMoreElements())14 15     {16 17     Order each=(Order) e.nextElement();18 19     Outstanding+=each.getAmount();20 21     }22 23     printDetails(outstanding);24 25 }
View Code

提炼后:

Void printOwing(){    Ddouble outstanding=previousAmount * 1.2;    print Banner();    Double outstanding=getOutstanding(outstanding);//Double outstanding=getOutstanding(previousAmount * 1.2);    printDetails(outstanding);}    Double getOutstanding(double initialValue)){    Ddouble outstanding=initialValue;    Enumeration e=_orders.elements();    While(e.hasMoreElements())    {    Order each=(Order) e.nextElement();    Outstanding+=each.getAmount();        }    Return outstanding();}                                                                                                    
View Code

 

读书笔记-重构方法之一:提炼方法(Extract Method)