《重構:改善既有代碼的設計》之於重構就相當於韻譜之於作詩。一個翻著韻書作詩的詩人一定是蹩腳的,但好的詩人卻要對那109個韻部了然於胸;同樣,一個好的程序員要求能夠主動自然地重構代碼,雖不應翻著重構手冊干活,但需對《重構:改善既有代碼的設計》中提到的70多個重構方法成竹在胸。然而,在達到這一境界之前,需要不斷的實踐和經驗積累,並且要先讀讀Fowler的這《重構:改善既有代碼的設計》。它在本質上是向我們推薦了一種優秀的編程習慣和編程態度。在領會這種重要思想的同時,我們也應該培養一種精益求精的工作態度,探索一條更適合自己的重構道路。
最後鄭重推薦,這是一部軟件開發的不朽經典,生動闡述重構原理和具體做法,是普通程序員進階到編程高手必須修煉的秘笈。
重構:改善既有代碼的設計 中文PDF清晰版+源代碼 下載見 http://www.linuxidc.com/Linux/2014-08/105065.htm
(一):重新組織自己的函數
問題:過長函數(Long Method) 往往需要我們通過手法提煉函數(Extract Method),把一段代碼從原函數裡面提煉出一段代碼放入一單獨函數中。遇到的問題主要有
臨時變量問題(Temp variable matter) 和參數問題(Parameter matter),
(1)、在處理臨時變量問題時我們提供(replace temp with query)去掉一些臨時變量。如果很多地方用到這個臨時變量,
可以是用Split temporary variable,將它變得容易替換,如果臨時變量太亂,可以引入Replace Method with Method Object代價是引入新的class。
(2)、處理參數使用remove Assignments to parameters。
最後函數分解以後使用Substitute Algorithm引入更清晰的算法
做法:在Extract Method 關鍵是要在函數名稱和函數體之間的語義距離,強化代碼的清晰度。一下是Exctract Method的三種實例
1) 沒有局部變量,直接提煉。2) 有局部變量,把這個局部變量作為參數傳入被提煉函數 3)如果需要對局部變量賦值,得需要使用remove Assignments to parameters
如果被賦值的局部變量只在被提煉的函數中被賦值,則把這個局部變量聲明到被提煉函數中。如果被賦值的局部變量需要在被提煉的函數其它的地方使用,則需要被提煉
函數返回一個被修改後的值。如果遇到返回的不止一個值,則最好的方法是再重新提煉一個新的方法,每次只返回一個值最佳。
(1)Inline Temp
如果有一個臨時變量,只被一個簡單的表達式賦值過一次。重構手法,將所有對該變量的引用動作,替換為對它賦值的那個表達式
double price = anOrder*basePrice();
return price>1000
替換=》 return anOrder*basePrice()>1000;
(2)Replace Temp with Query
一個臨時變量保存了一個表達式的結果,需要把這個表達式提煉到一個獨立函數裡,在所以應用到這個臨時變量的地方替換為一個新函數的調用。
double basePrice = _quantity*_item;
if (basePrice>1000){
return basePrice*0.95;
} else {
return basePrice*0.98;
}
替換=》
public basePrice(){
return _quantity*_item;
}
if (basePrice()>1000) {
return basePrice*0.95
} else {
return basePrice*0.98;
}
(3) Introduce Explaining Variable
將復雜表達式的結果放入一個臨時變量裡面,以此變量名來解釋表達式用途
if(platform.toUpperCase().indexOf("MSC")>-1 && browers.toUpperCase.indexOf("IE")>-1 && size()>0){...}
替換=》
final boolean isMSC = platform.toUpperCase().indexOf("MSC");
final boolean isBrowsers = browers.toUpperCase.indexOf("IE");
final boolean isResize = size()>0;
if(isMSC && isBrowsers && isResize){...}。
這個也可以使用Replace Temp with Query來重構
public boolean isMSC(){retrun platform.toUpperCase().indexOf("MSC");}
public boolean isBrowsers(){browers.toUpperCase.indexOf("IE");}
public boolean isResize(){size()>0}
if(isMSC() && isBrowsers() && isResize()){...}
(4) Split Temporary Variable 解剖臨時變量
在程序中臨時變量超過一次,它既不是循環變量,也不是集中臨時變量。則每次給臨時變量賦值,創造一個獨立的,對應的臨時變量
double temp = 2*(width+height);
System.out.println(temp);
temp = width*height;
System.out.println(temp);
替換=》
final double perimeter = 2*(width+height);
System.out.println(perimeter);
final double area = widht * height;
System.out.println(area);
final 關鍵字的作用是讓這兩個變量只被賦值一次
(5) Remove Assignments Parameters
對一個參數進行賦值操作,以一個臨時變量來取代該參數的位置
int disCount(int nInput, int quantity){
if (nInput>50){
nInput -= 2;
}
替換=》
int disCount(int nInput, int quantity){
int result = nInput;
if (nInput>50){
result -=2;
}
}
(6) Replace Mehtod with Method Object
將所有的局部變量都變成函數對象(Mehtod Class)的值域(Field)。然後你就可以對這個新的對象使用Extract Method 來創造新的函數
(7) Substitute Algorithm(替換算法)
String findPersion(String[] persion){
for (int i = 0; i<persion.length; i++){
if(persion[i].equals("Don")){
return "Don";
}
if(persion[i].equals("John")){
return "John";
}
if(persion[i].equals("Kent")){
return "Kent";
}
}
}
替換=》
String findPersion(String[] persion){
List<String> perList = Arrays.asList(new String[]{"Don","John","Kent"});
for (int i = 0; i<persion.length; i++){
if(perList.containts(persion[i])){
return persion[i];
}
}
return "";
}
更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-08/105066p2.htm