重构--Extract Method(提炼函数)(四)
2017-08-15 21:30
288 查看
重构方式
将下面的代码放进一个独立函数中,并让函数名称解释该函数的用途
动机
当出现一个过长的函数或者一段需要注释才能让人理解用途的代码,都可以将这段代码放进一个独立函数中;
函数粒度很小,函数被复用的机会就更大;
可以使高层函数读起来像一系列注释;
如果函数都是细粒度,那么函数的覆写也会更容易些;
做法
创建一个新函数,根据这个函数的意图来对它命名(以它"做什么"来命名,而不是以它"怎样做"命名);
将提炼出的代码从源函数复制到新建的目标函数中;
仔细检查提炼出的代码,看看其中是否引用了"作用域限于源函数"的变量(包括局部变量和源函数参数);
检查是否有"仅用于被提炼代码段"的临时变量。如果有,在目标函数中将它们声明为临时变量;
检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果一个临时变量被修改了,看看是否可以将被提炼代码段处理为一个查询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地体谅出来。你可能需要先"分解临时变量",然后再尝试提炼。也可以用"以查询替代临时变量"将临时变量消灭掉;
将被提炼代码段中需要读取的局部变量,当作参数传给目标函数;
处理完所有局部变量之后,进行编译;
在源函数中,将被提炼代码段替换为对目标函数的调用;
范例:无局部变量
问题函数:
提炼出"打印横幅"的代码:
范例:有局部变量
第一种情况:被提炼代码段只是读取这些变量的值,并不修改它们。这种情况下,可以简单地将它们当作参数传给目标函数。这种方式可以处理多个局部变量或者该变量是个对象:
第二种情况(对局部变量再赋值):此情况只讨论被赋值的临时变量;
示例代码:
问题1:如果源函数的参数被赋值,请马上"移除对参数的赋值"!
被赋值的临时变量分两种情况:
该变量只在被提炼代码段中使用。可以将这个临时变量的声明移到被提炼代码段中,然后一起提炼出去;
被提炼代码段之外的代码也使用了这个变量,分两种情况:
如果这个变量在被提炼代码段之后,未再被使用,只需直接在目标函数中修改它就可以了;
如果被提炼代码段之后的代码还使用了这个变量,需要让目标函数返回该变量改变后的值;
了解以上情况后,现在尝试将"计算"代码提炼出来:
Enumeration变量e只在被提炼代码段中用到,所以可以将它整个搬到新函数中。double变量outstanding在被提炼代码段内外都被用到,所以必须让提炼出来的新函数返回它。编译通过后,把回传值改名:
outstanding变量只是很单纯地被初始化为一个明确初值,所以可以只在新函数中对它初始化。如果代码还对这个变量做了其他处理,就必须将它的值作为参数传给目标函数。对于这种变化,最初的代码可能是这样:
提炼代码:
通过编译后,将变量outstanding的初始化过程进行整理:
问题:需要返回的变量不止一个,该怎么办?
挑选另一块代码来提炼。尽可能让函数都只返回一个值,用多个函数来返回多个值;
写在最后
临时变量往往为数众多。这种情况下,可以尝试"以查询取代临时变量"的方式减少临时变量。如果这样做无效,可以尝试"以函数对象取代函数";
将下面的代码放进一个独立函数中,并让函数名称解释该函数的用途
void printOwing(double amount){ printBanner(); //print details System.out.println("name:"+_name); System.out.println("amount"+amount); } |
void printOwing(double amount){ printBanner(); printDetails(amount); } void printDetails(double amount){ System.out.println("name:"+_name); System.out.println("amount"+ amount); } |
当出现一个过长的函数或者一段需要注释才能让人理解用途的代码,都可以将这段代码放进一个独立函数中;
函数粒度很小,函数被复用的机会就更大;
可以使高层函数读起来像一系列注释;
如果函数都是细粒度,那么函数的覆写也会更容易些;
做法
创建一个新函数,根据这个函数的意图来对它命名(以它"做什么"来命名,而不是以它"怎样做"命名);
将提炼出的代码从源函数复制到新建的目标函数中;
仔细检查提炼出的代码,看看其中是否引用了"作用域限于源函数"的变量(包括局部变量和源函数参数);
检查是否有"仅用于被提炼代码段"的临时变量。如果有,在目标函数中将它们声明为临时变量;
检查被提炼代码段,看看是否有任何局部变量的值被它改变。如果一个临时变量被修改了,看看是否可以将被提炼代码段处理为一个查询,并将结果赋值给相关变量。如果很难这样做,或如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地体谅出来。你可能需要先"分解临时变量",然后再尝试提炼。也可以用"以查询替代临时变量"将临时变量消灭掉;
将被提炼代码段中需要读取的局部变量,当作参数传给目标函数;
处理完所有局部变量之后,进行编译;
在源函数中,将被提炼代码段替换为对目标函数的调用;
范例:无局部变量
问题函数:
void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; //print banner System.out.println("*******************"); System.out.println("***Customer Owes***"); System.out.println("*******************"); //calchlate outstanding while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } //print details System.< 142cc strong>out[/b].println("name:" + _name); System.out.println("amount" + outstanding); } |
void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); //calchlate outstanding while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println("name:" + _name); System.out.println("amount" + outstanding); } void printBanner() { //print banner System.out.println("*******************"); System.out.println("***Customer Owes***"); System.out.println("*******************"); } |
第一种情况:被提炼代码段只是读取这些变量的值,并不修改它们。这种情况下,可以简单地将它们当作参数传给目标函数。这种方式可以处理多个局部变量或者该变量是个对象:
void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); //calchlate outstanding while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println("name:" + _name); System.out.println("amount" + outstanding); } |
void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); //calchlate outstanding while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } void printDetails(double outstanding) { //print details System.out.println("name:" + _name); System.out.println("amount" + outstanding); } |
示例代码:
void printOwing(){ Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); //calchlate outstanding while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } |
被赋值的临时变量分两种情况:
该变量只在被提炼代码段中使用。可以将这个临时变量的声明移到被提炼代码段中,然后一起提炼出去;
被提炼代码段之外的代码也使用了这个变量,分两种情况:
如果这个变量在被提炼代码段之后,未再被使用,只需直接在目标函数中修改它就可以了;
如果被提炼代码段之后的代码还使用了这个变量,需要让目标函数返回该变量改变后的值;
了解以上情况后,现在尝试将"计算"代码提炼出来:
void printOwing(){ printBanner(); double outstanding = getOutstanding(); printDetails(outstanding); } double getOutstanding() { Enumeration e = _orders.elements(); double outstanding = 0.0; while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } return outstanding; } |
double getOutstanding() { Enumeration e = _orders.elements(); double result = 0.0; while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); result += each.getAmount(); } return result; } |
void printOwing(double previousAmount){ Enumeration e = _orders.elements(); double outstanding = previousAmount * 1.2; printBanner(); while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } |
void printOwing(double previousAmount){ double outstanding = previousAmount * 1.2; printBanner(); outstanding = getOutstanding(outstanding); printDetails(outstanding); } double getOutstanding(double initialValue) { double result = 0.0; Enumeration e = _orders.elements(); while(e.hasMoreElements()){ Order each = (Order)e.nextElement(); result += each.getAmount(); } return result; } |
void printOwing(double previousAmount){ printBanner(); double outstanding = getOutstanding(previousAmount * 1.2); printDetails(outstanding); } |
挑选另一块代码来提炼。尽可能让函数都只返回一个值,用多个函数来返回多个值;
写在最后
临时变量往往为数众多。这种情况下,可以尝试"以查询取代临时变量"的方式减少临时变量。如果这样做无效,可以尝试"以函数对象取代函数";
相关文章推荐
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- java 重构学习2:提炼函数(Extract method)
- 重构手法01:Extract Method (提炼函数)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 《重构 改善既有代码的设计》学习笔记 2 -- Extract Method(提炼函数)
- 重构改善既有代码设计--重构手法01:Extract Method (提炼函数)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构:Extract Method (提炼函数)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构1:Extract Method提炼函数
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)
- 重构--Extract Method(提炼函数)(四)