第2章 重新组织函数:提炼函数

Posted 浅墨浓香

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第2章 重新组织函数:提炼函数相关的知识,希望对你有一定的参考价值。

1. 提炼函数(Extract Method)

1.1 动机

(1)函数的粒度小,被复用的机会就会更大。而且细粒度的函数覆写也会更容易。

(2)简短而命名良好的函数,会使高层函数读起来就像一系列注释

1.2 做法

(1)创建一个新函数,并根据函数的意图命名(以它“做什么”来命名,而不是以它“怎么做”命名)

(2)将提炼出的代码从源函数复制到新建的目标函数中。

(3)仔细检查提炼出的代码,看看其中是否引用了“作用域限于源函数”的变量(如即是还是使用了源函数中的局部变量或参数)

(4)检查是否有“仅用于被提炼代码段”的临时变量。如果有,在目标函数中将它们声明为临时变量。

(5)检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果有一个临时变量的值被修改了,看看是否可以被将提炼代码炼处理为一个查询,并将结果赋值给相关变量。如果被修改的变量不止一个,可以先用Split Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query将临时变量消灭掉。

(6)将被提炼代码段中需要读取的局部变量,当作参数传给目标函数。

(7)在源函数中,将被提炼代码段替换为对目标函数的调用。

1.3 范例

//重构前(Java)

//源函数
void printOwing(double previousAmount)
{
    Enumeration e = _orders.elements(); //_orders是类的成员变量
    double outstanding = previousAmount * 1.2;
    
    //print banner(无局部变量)
    System.out.println("*****************************");
    System.out.println("********Customer Owes********");
    System.out.println("*****************************");
    
    //calculate outstanding
    while(e.hasMoreElements())
    {
        Order each = (Order) e.nextElement();
        outstanding += each.getAmount();
    }
    
    //print details
    System.out.println("name:" + _name);//_name为成员函数
    System.out.println("amount" + outstanding);//outstanding为局部变量
}

//重构后

//经Extract Method 提炼后的函数
void printOwing(double previousAmount)
{    
    printBanner();
    
    double outstanding = getOutstanding(previousAmount * 1.2);
    
    printDetail(outstanding);
}


//无局部变量,直接提取(函数名以意图命令)
void printBanner()
{
    //print banner
    System.out.println("*****************************");
    System.out.println("********Customer Owes********");
    System.out.println("*****************************");    
}

//有局部变量outstanding,将其作为参数传递给目标函数(函数名以意图命令)
void printDetails(double outstanding)
{
    System.out.println("name:" + _name);
    System.out.println("amount" + outstanding);
}

//对局部变量再赋值,分为两种情况:(函数名以意图命令)
//1.该变量只在被提炼代码中使用时,可直接将该变量的声明移到目标函数中
//2.该变量在被提炼代码之个也使用了这个变量,又分两种情况
//   A.变量在被提炼代码之后未再被使用,只需直接在目标函数中修改它便可
//   B.变量在被提炼代码之后还被使用,可让目标函数返回修改后的变量(本例属这情况)
double getOutStanding(double initValue)
{
   //源函数中变量e只在被提炼代码段中用到,可搬到新函数中定义
    Enumeration e = _orders.elements();
    
    //源函数中outstanding在被提炼代码段内外都被使用,可让目标函数返回该值
    double result = initValue; //outstanding
    
    //calculate outstanding
    while(e.hasMoreElements())
    {
        Order each = (Order) e.nextElement();
        result += each.getAmount();
    }    
    
    return result;
}

1.4 思考

(1)Extract Method最大的困难是处理局部变量,而临时变量是其中之一。

(2)可以用Replace Temp with Query去掉所有可去掉的临时变量。

(3)如果很多地方使用了某个临时变量,可用Split Temporary Variable将它变得比较容易替换。

(4)也可以用Replace Method with Method Object引入一个新类也处理临时变量。

(5)参数带来的问题比较容易处理。但如果在函数内赋值给参数了,可以用Remove Assignments to Parameters来处理。

以上是关于第2章 重新组织函数:提炼函数的主要内容,如果未能解决你的问题,请参考以下文章

重构改善既有代码的设计--第6章--重新组织函数

2重新组织函数

2重新组织函数

extract method(重新组织函数)

第2章 重新组织函数:函数对象替换算法

重构改善既有代码设计--重构手法 之重新组织你的函数总结