重構是對軟件內部結構的一種調整,目的是在不改變軟件之可察性前提下,提高其可理解性,降低其修改成本。關于重構的至理明言如下:
任何一個傻瓜都能寫出計算器可以理解的代碼,唯有寫出人類容易理解的代碼,才是優秀的程序員;
事不過三,三則重構;
當你感覺需要撰寫注釋,請先嘗試重構,試著讓所有的注釋變得多余;
當你發現自己需要為程序增加一個特性,而代碼結構使你無法方便的這樣做,就先重構那個程序;
重構之前,必須建立一套可靠的測試機制;
寫軟件就像種樹,優秀的程序員挖成小坑后隨及填好,繼續挖下一個,只會產生一系列小坑,不會有大坑,菜鳥則不會意識到所挖的坑正在變大,還是不停的挖,直到自己掉進大坑,爬不出來,陷入無盡的痛苦深淵;
開發時間越長,越能體會垃圾代碼的痛苦,卻不知道如何改進;
Kent Beck:我不是一個偉大的程序員,我只是個有著一些優秀習慣的好程序員而已;
變量(Variable)
不要定義一個臨時變量多次重復使用,臨時變量定義仍然應該可以自解釋,從變量名稱能夠很好的理解變量的含義和作用。在定義一個臨時變量后需要有一段業務邏輯才能夠完成對臨時變量的賦值的時候,可以考慮將這段邏輯抽取到一個獨立的方法。
doublegetPrice(){
int basePrice = _quantity* _itemPrice;
double discountFactor;
if (basePrice > 1000) discountFactor = 0.95;
else discountFactor = 0.98;
return basePrice * discountFactor;
}
重構為:
double getPrice(){
return basePrice()* discountFactor();
}
private int basePrice(){
return _quantity* _itemPrice;
}
private double discountFactor(){
if (basePrice()> 1000) return0.95;
else return 0.98;
}
當遇到復雜的表達式的時候,需要引入解釋變量,因為復雜的表達式很難進行自解釋。
if ((platform.toUpperCase().indexOf("MAC")> -1)&&
(browser.toUpperCase().indexOf("IE")> -1)&&
wasInitialized()&& resize> 0 )
{
// do something
}
重構為:
final booleanisMacOs = platform.toUpperCase().indexOf("MAC")>-1;
final boolean isIEBrowser =browser.toUpperCase().indexOf("IE") > -1;
final booleanwasResized = resize >0;
if (isMacOs&& isIEBrowser&& wasInitialized()&& wasResized){
// do something
}
減少對全局變量的使用,第一個是全局變量的生命周期很難控制,資源本身無法得到很快的釋放,其二是過多使用全局變量導致在調用方法的時候很難完全清楚方法說需要的入口數據信息,其三,多處都可以對全局變量賦值,我們很難立刻定位到當前全局變量的值來源自哪里?
分解方法(Extract Method)
一個較大的方法往往也會分為多個小的段落,step1,step2,step3,在每一個步驟都會考慮添加注釋說明。而這些相對較為獨立的步驟就可以分解為不同的方法,在分解后方法名可以自解釋方法的功能而不再需要額外的注釋。在一個類里面如果方法里面有一段代碼在多個方法中重復出現,需要抽取該類的公用方法。在多個不同的類中有一段代碼重復出現,需要考慮將公用代碼放到公用類中形成公用方法。
方法名需要很好的自解釋方法的功能,方法的返回盡量單一,方法的入口參數太多的時候應該考慮使用集合,結構或數據對象進行參數的傳遞。參數的傳遞可能出傳遞的是引用,但不要去修改入口參數的值。
不要因為一個方法里面只有一行,兩行很短而不考慮去分解,分解的時候更多的是考慮代碼的自解釋性。代碼本身不是解釋的技術實現機制,而是解釋的業務規則和需求。如果代碼不是解釋的業務規則和需求,那么其它人員就很難快速理解。
引入方法對象來取代方法,當發現一個方法只用到該類里面的幾個關鍵屬性,方法和類里面其它的方法交互很少,輸出單一。由于該方法和這幾個屬性內聚性很強而和該類其它部分松耦合,因此可以考慮將方法和這部分屬性移出形成一個單獨的方法對象。
移動方法,類的職責要單一,一個類的方法更多用到了別的類的屬性,這個方法可能更適合定義在那個類中。
class Account...
private AccountType_type;
private int_daysOverdrawn;
double overdraftCharge(){
if (_type.isPremium()){
double result = 10;
if (_daysOverdrawn > 7) result += (_daysOverdrawn -7)* 0.85;
return result;
}
else return _daysOverdrawn * 1.75;
}
double bankCharge(){
double result = 4.5;
if (_daysOverdrawn > 0) result +=overdraftCharge();
return result;
}
重構為:
classAccount...
private AccountType _type;
private int _daysOverdrawn;
double overdraftCharge(){
return _type.overdraftCharge(_daysOverdrawn);
}
double bankCharge(){
double result = 4.5;
if (_daysOverdrawn > 0)
result += _type.overdraftCharge(_daysOverdrawn);
原文轉自:http://kb.cnblogs.com/page/68471/