`
kuyuyingzi
  • 浏览: 54852 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

重新组织函数

1、ExtractMethod(提炼函数)

动机:你有一段代码可以被组织在一起并独立出来。

做法:将这段代码放进一个独立函数中,并让函数名称解释该函数的用途。

如下面的实例,提炼后的代码变得更清晰易读。

代码1:

voidprintOwing(doublepreviousAmount)){

Enumeratione=_orders.elemnets();

doubleoutstanding=previousAmount*1.2);

//pirntbanner

System.out.println("***************************");

System.out.println("******CustomerOwes******");

System.out.println("***************************");

//calculateoutstanding

while(e.hasMoreElements()){

Ordereach=(Order)e.nextElement();

outstanding+=each.getAmout();

}

//printdetails

System.out.print("name:"+_name);

System.out.print("amout:"+outstanding);

}

代码2:

voidprintOwing(doublepreviousAmount){

printBanner();

doubleoutstanding=getOutstanding(previousAmount*1.2);

printDetails(outstanding);

}

voidprintBanner(){

System.out.println("***************************");

System.out.println("******CustomerOwes******");

System.out.println("***************************");

}

doublegetOutstanding(doubleinitialValue){

doubleresult=initalValue;

Enumeratione=_orders.elemnets();

while(e.hasMoreElements()){

Ordereach=(Order)e.nextElement();

result+=each.getAmout();

}

returnresult;

}

voidprintDetails(doubleoutstanding){

System.out.print("name:"+_name);

System.out.print("amout:"+outstanding);

}

2、InlineMethod(内涵函数)

动机:一个函数的本体与名称同样清楚易懂。

做法:在函数调用点插入函数本体,然后移除该函数。

代码1

intgetRating(){

return(moreThanFiveLateDeliveries())?2:1;

}

booleanmoreThanFiveLateDeliveries(){

return_numberOfLateDeliveries>5;

}

代码2

intgetRating(){

return(_numberOfLateDeliveries>5)?2:1;

}

3、InlineTemp(内联临时变量)

动机:你有一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法。

做法:将所有对该变量的引用动作,替换为对它赋值的那个表达式自身。

备注:检查该变量是否真的被赋值一次,可以将该变量声明为final,然后编译。

代码1

doublebasePrice=anOrder.basePrice();

return(basePrice>1000);

代码2

return(anOrder.basePrice()>1000);

4、ReplaceTempwithQuery(以查询取代临时变量)

动机:临时变量的问题在于:他们是暂时的,而且只能在所属函数内使用。由于临时变量只在所属函数内可见,所以他们会驱使你写更长的函数,因为只有这样你才能访问到需要的临时变量。如果把临时变量替换为一个查询,那么同一个类中的所有函数都将可以获得这份信心。这将带给你极大帮助,使你能够为这个类编写更清晰的代码。

做法:将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可被其他函数使用。

代码1

doublebasePrice=_quantity*_itemPrice;

if(basePrice>1000)

reutrnbasePrice*0.95;

else

returnbasePrice*0.98;

代码2

if(basePrice()>1000)

returnbasePrice()*0.95;

else

returnbasePrice()*0.98;

....

doublebasePrice(){

return_quantity*_itemPrice;

}

这个重构手法较为简单,如果临时变量比较多,还需要运用SplitTemporaryVariable(拆分临时变量)或SeparateQueryfromModifier(将查询函数和修改函数分离)使情况变得简单一些,然后再替换临时变量。如果你想替换的临时变量是用来收集结果的(例如循环中的累加值),就需要将某些程序逻辑(例如循环)复制到查询函数去。

代码1

doublegetPrice(){

intbasePrice=_quantity*_itemPrice;

doublediscountFactor;

if(basePrice>1000)discountFactor=0.95;

elsediscountFactor=0.98;

returnbasePrice*discountFactor;

}

代码2

doublegetPrice(){

returnbasePrice()*discountFactor();

}

privateintbasePrice(){

return_quantity*_itemPrice;

}

privatedoublediscountFactor(){

if(basePrice()>1000)return0.95;

elsereturn0.98;

}

5、IntroduceExplainingVariable(引入解释性变量)

动机:你有一个复杂的表达式。在条件逻辑中,IntroduceExplainingVariable特别有价值:你可以用这项重构将每个条件子句提炼出来,以一个良好命名的临时变量来解释对应条件子句的意义。使用这项重构的另一种情况是,在较长算法中,可以运用临时变量来解释,每一步运算的意义。

代码1

if((platform.toupperCase().indexOf("MAC")>-1)&&

(browser.toUpperCase().indexOf("IE")>-1)&&

wasInitialized()&&resize>0){

//dosomething

}

代码2

finalbooleanisMacOs=platform.toupperCase().indexOf("MAC")>-1;

finalbooleanisIEBrowser=browser.toUpperCase().indexOf("IE")>-1;

finalbooleanwasResized=resize>0;

if(isMacOs&&isIEBrowser&&wasResized){

//dosomething

}

类似的,我们也经常用ExtractMethod(提炼函数)来解释表达式用途,如下示例:

代码1

doubleprice(){

//priceisbaseprice-quantitydiscount+shipping

return_quantity*_itemPrice-

Math.max(0,_quantity-500)*_itemPrice*0.05+

Math.min(_quantity*_itemPrice*0.1,100.0);

}

代码2

doubleprice(){

returnbasePrice()-quantityDiscount()+shipping();

}

privatedoublequantityDiscount(){

returnMath.max(0,_quantity-500)*_itemPrice*0.05;

}

privatedoubleshipping(){

returnMath.min(basePrice()*0.1,100.0);

}

privatedoublebasePrice(){

return_quantity*_itemPrice;

}

IntroduceExplainingVariable(引入解释性变量)和ExtractMethod(提炼函数)比较:两者都可以达到解释表达式的效果,我觉得主要看临时变量是否被公用到,如果不是,则用引入解释性变量即可。

6、SplitTemporaryVariable(分解临时变量)

场景:你的程序有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于手机计算结果。

分析:这种临时变量应该制备赋值一次。如果它们被赋值超过一次,就意味它们在函数中承担了一个以上的责任。如果临时变量承担多个责任,它就应该被替换(分解)为多个临时变量,每个变量只承担一个责任。同一个临时变量承担两件不同的事情,会令代码阅读者糊涂。

代码1

doubletemp=2*(_height+_width);

System.out.println(temp);

temp=_height*_width;

System.out.println"temp);

代码2

finaldoubleperimeter=2*(_height+_width);

System.out.println(perimeter);

finaldoublearea=_height*_width;

System.out.println(area);

7、RemoveAssignmentstoParameters(移除对参数的赋值)

场景:代码对一个参数进行赋值

做法:以一个临时变量取代该参数的位置。

分析:从本质上说,参数是对象的引用,而对象的引用时按值传递的。因此我可以修改参数对象的内部状态(属性),但对参数对象重新赋值是没有意义。

代码1

intdiscount(intinputVal,intquantity,intyearToDate){

if(inputVal>50)inputVal-=2;

}

代码2

intdiscount(intinputVal,intquantity,intyearToDate){

intresult=inputVal;

if(inputVal>50)result-=2;

}

我还可以为参数加上关键词final,从而强制它遵循“不对参数赋值”这一惯例:

代码1

intdiscount(intinputVal,intquantity,intyearToDate){

if(inputVal>50)inputVal-=2;

if(quantity>100)inputVal-=1;

if(yearToDate>10000)inputVal-=4;

}

代码2

intdiscount(finalintinputVal,finalintquantity,finalintyearToDate){

intresult=inputVal;

if(inputVal>50)result-=2;

if(quantity>100)result-=1;

if(yearToDate>10000)result-=4;

}

不过我得承认,我不经常使用final来修饰参数,因为我发现,对于提高短函数的清晰度,这个方法并无太大帮助。我通常会在较长的函数中使用它,让它帮助我检查参数是否被做修改。

8、ReplaceMethodwithMethodObject(以函数对象取代函数)

动机:你有一个大型函数,其中对局部变量的使用使你无法采用ExtractMethod(提炼函数)。

做法:将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后你可以在同一个对象中将这些大型函数分解为多个小型函数。

9、SubsituteAlgorithm(替换算法)

动机:你需要把某个算法替换为另一个更清晰的算法。

做法:将函数本体替换为另一个算法。

代码1

StringfoundPerson(String[]people){

for(inti=0;i<people.length;i++){

if(people[i].equals("Don")){

return"Don";

}

if(people[i].equals("John")){

return"John";

}

if(people[i].equals("Kent")){

return"Kent";

}

}

return"";

}

代码2

StringfoundPerson(String[]people){

Listcandidates=Arrays.asList(newString[]{"Don","John","Kent");

for(inti=0;i<people.length;i++){

if(candidates.contains(people[i])){

returnpeople[i];

}

}

return"";

}

分享到:
评论

相关推荐

    重构-改善既有代码的设计 中文版.pdf

    第6章 重新组织你的函数 6.1 Extract Method(提炼函数) 6.2 Inline Method(将函数内联化) 6.3 Inline Temp(将临时变量内联化) 6.4 Replace Temp With Query(以查询取代临时变量) 6.5 Introduce Explaining ...

    重构-改善既有代码的设计

    第6章 重新组织函数 109 6.1 Extract Method(提炼函数) 110 6.2 Inline Method(内联函数) 117 6.3 Inline Temp(内联临时变量) 119 6.4 Replace Temp with Query(以查询取代临时变量) 120 6.5 ...

    重构:改善既有代码的设计(中文高清版)

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    重构_改善既有代码的设计.pdf

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    重构-改善既有代码的设计 中文版

    第6章 重新组织你的函数 6.1 Extract Method(提炼函数) 6.2 Inline Method(将函数内联化) 6.3 Inline Temp(将临时变量内联化) 6.4 Replace Temp With Query(以查询取代临时变量) 6.5 Introduce Explaining ...

    重构_改善既有代码的设计[高清版]【已进行内容识别处理,可搜索,可编辑+有目录】

    2.6 重构与设计······ ·· · · ······· ·· ···· · ··· ·· · · ··· ·· ·· ····· · · · ·· ·· ·· ··· ·· ·· · ·· ·· ···· · ···· · · ·...

    重构:改善既有代码的设计(中文版).

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    重建——改善既有代码的设计

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    重构-改善既有代码的设计(chm清晰版)

    本书解释重构的原理(principles)和最佳实践方式(best practices),并指出何时何地你应该开始挖掘你的代码以求改善。本书的核心是壹份完整的重构名录(catalog of refactoring),其中每壹项都介绍壹种经过实证的...

    重构-改善既有代码的设计+中文版

    Chapter 1:Refactoring,a First Example 重构,第一个例子   The Starting Point 起点   The First Step in Refactoring 重构第一步   Decomposing and Redistributing the Statement Method 分解并重组...

    重构:改善既有代码的设计.[美]Martin Fowler.epub【文字版手机格式】

    第6章 重新组织函数 6.1 Extract Method(提炼函数) 6.2 Inline Method(内联函数) 6.3 Inline Temp(内联临时变量) 6.4 Replace Temp with Query(以查询取代临时变量) 6.5 Introduce Explaining Variable(引入...

    重构改善既有代码的设计

    重新组织你的函数,代码重构方面的好书,公司内部强烈推荐。

    重构_改善既有代码的设计

    第 6 章:重新组织你的函数(Composing Methods) 第 7 章:在对象之间移动特性(Moving Features Between Objects) 第 8 章:重新组织你的数据(Organizing Data) 第 9 章:简化条件表达式(Simplifying...

    重构—改善既有代码的设计

    6、1重新组织你的函数(ComposingMethods) 6、2在对象之间移动特性(MovingFeaturesBetweenObjects) 6、3重新组织你的数据(OrganizingData) 6、4简化条件表达式(SimplifyingConditionalExpressions) ...

    《重构改善既有代码的设计(2010年版)》(Martin Fowler[美] 著,熊节 译)

    第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...

    PHP 杂谈《重构-改善既有代码的设计》之三 重新组织数据

     承接上文的PHP 杂谈《重构-改善既有代码的设计》之 重新组织你的函数继续重构方面的内容。   这章主要针对数据的重构。   1、争论的声音——直接访问Field还是通过函数(Accessor)访问Field  2.修改Array为...

Global site tag (gtag.js) - Google Analytics