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

第六章 重新组织你的函数

6.1  Extract Method(提炼方法)

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

 

1 void printOwing (douoble amount)
2 {
3     printBanner();
4     //print details
5     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 banner
12 
13     System.out.println(“*****************************”);
14 
15     System.out.println(“********Customer Owes********”);
16 
17     System.out.println(“*****************************”);
18 
19  
20 
21     //calculate outstanding
22 
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 details
36 
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 outstanding
12 
13     While(e.hasMoreElements())
14 
15     {
16 
17     Order each=(Order) e.nextElement();
18 
19     Outstanding+=each.getAmount();
20 
21     }
22 
23     //print details
24 
25     System.out.println(“name:”+_name);
26 
27     System.out.println(“amount”+outstanding);
28 
29     }
30 
31     Void printBanner()
32 
33     {
34 
35     //print banner
36 
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 outstanding
12 
13     While(e.hasMoreElements())
14 
15     {
16 
17     Order each=(Order) e.nextElement();
18     
19     Outstanding+=each.getAmount();
20 
21     }
22 
23     //print details
24 
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 outstanding
12 
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 outstanding
12 
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 outstanding
12 
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

 

原文地址:https://www.cnblogs.com/yynzh21/p/3951795.html