重新组织函数
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"";
}
分享到:
相关推荐
第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 ...
第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 ...
本书解释重构的原理(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 分解并重组...
第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) ...
第6章 重新组织函数109 6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 ...
承接上文的PHP 杂谈《重构-改善既有代码的设计》之 重新组织你的函数继续重构方面的内容。 这章主要针对数据的重构。 1、争论的声音——直接访问Field还是通过函数(Accessor)访问Field 2.修改Array为...