首页 > 代码库 > 读书笔记-重构方法之一:提炼方法(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 }
我们可以轻松的提炼出 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 }
范例二:有局部变量
局部变量最简单的情况是:被提炼码只是读取这些变量的值,并不修改它们,这种情况下可以简单地将它们当做参数传给目标函数。
提炼前:
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 }
提炼后:
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 }
处理多个局部变量也可以使用上述这种方法。
范例三:对局部变量再赋值
如果被提炼码对局部变量赋值,问题就变得复杂了,这里我们只讨论临时变量的问题。
被赋值的临时变量也分为两种情况。比较简单的情况是:这个变量只是在被提炼码中使用,这样,可以将这个临时变量的声明一道被提炼码中,然后一起提炼出去。另一种情况是:被提炼码之外的代码也是用了这个变量。
提炼前:
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 }
提炼后:
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 }
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 }
提炼后:
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();}
读书笔记-重构方法之一:提炼方法(Extract Method)