讀這本書的初衷是想對(duì)自己的代碼以旁觀者的角度進(jìn)行一番審查,所以選擇了這本網(wǎng)上大家都推薦的書籍——《重構(gòu) 改善既有代碼的設(shè)計(jì)》厕九。這本書上提供了很多重構(gòu)代碼的技巧方法蓖捶。個(gè)人認(rèn)為重構(gòu)最直觀的感受是“提高代碼的閱讀效率”,什么意思扁远?就是當(dāng)接手你代碼的同事能夠很快的理解這段代碼的意思以及編寫上的思維角度俊鱼,就是能夠讀懂你當(dāng)時(shí)處理數(shù)據(jù)的邏輯方式。另一方面就是“提高代碼的質(zhì)量”畅买,接手工作的同事在閱讀的同時(shí)能夠擱在心里連連稱贊這段代碼編寫方式并闲,說明你的重構(gòu)是有效。
一谷羞、重新組織函數(shù)
1帝火、Extract Method(提煉函數(shù))(P110)
“你有一段代碼可以被組織在一起并獨(dú)立出來”
Extract Method個(gè)人感覺是重構(gòu)代碼最常用的一個(gè)方法,在code review或者自我檢查代碼的時(shí)候,應(yīng)該都會(huì)用到這個(gè)方法犀填。
動(dòng)機(jī):
過長(zhǎng)的函數(shù)或者需要注釋才能讓人理解用途的代碼蠢壹,這個(gè)時(shí)候就需要考慮將這段代碼放進(jìn)一個(gè)獨(dú)立的函數(shù)。
當(dāng)你發(fā)現(xiàn)代碼中有大量的注釋來解釋這段代碼的用途的時(shí)候九巡,你就需要著手對(duì)這段代碼進(jìn)行重構(gòu)提煉了图贸,這也是新手重構(gòu)代碼的入口。
做法:
(1)創(chuàng)造一個(gè)新函數(shù)冕广,根據(jù)這個(gè)函數(shù)的意圖對(duì)它來命名(命名也是重構(gòu)的一種方法)求妹,命名要做到“見名之意”,讓別人看到名字就知道這段代碼的用途
(2)將提煉出的代碼從源函數(shù)復(fù)制到新建的目標(biāo)函數(shù)中
(3)檢查變量(局部變量和源函數(shù)參數(shù))佳窑,當(dāng)被提煉代碼段中需要讀取局部變量時(shí)制恍,這是就需要將局部變量當(dāng)作參數(shù)傳給目標(biāo)函數(shù);當(dāng)有臨時(shí)變量?jī)H作用于被提煉代碼段時(shí)神凑,在目標(biāo)函數(shù)中將它們聲明為臨時(shí)變量净神。這部分是整個(gè)Extract Method的精髓所在,需要處理好
(4)處理完所有局部變量之后溉委,進(jìn)行編譯
(5)在源函數(shù)中鹃唯,將被提煉斷碼段替換為對(duì)目標(biāo)函數(shù)的調(diào)用
(6)編譯,測(cè)試
提煉函數(shù)這種方式瓣喊,可以直接使用IDE工具中的快捷鍵坡慌,可以很方便的幫你處理第三個(gè)步驟中的變量,自動(dòng)的檢測(cè)被提煉代碼段所需要的一些參數(shù)
2藻三、Replace Temp with Query(以查詢?nèi)〈R時(shí)變量)
將這個(gè)表達(dá)式提煉到一個(gè)獨(dú)立函數(shù)中洪橘。將這個(gè)臨時(shí)變量的所有引用點(diǎn)替換為對(duì)新函數(shù)的調(diào)用。此后棵帽,新函數(shù)就可能被其他函數(shù)使用熄求。
看到這中重構(gòu)方式之后,自己也經(jīng)常在代碼中運(yùn)用這中手段逗概。去掉一些臨時(shí)變量的運(yùn)用弟晚,簡(jiǎn)化一些代碼。
動(dòng)機(jī):
臨時(shí)變量是暫時(shí)的逾苫,只能在所屬函數(shù)內(nèi)使用卿城。由于臨時(shí)變量只在所屬函數(shù)內(nèi)可見,所以會(huì)驅(qū)使寫出更長(zhǎng)的函數(shù)铅搓。如果把臨時(shí)變量替換為一個(gè)查詢瑟押,那么同一個(gè)類中的所有函數(shù)都將可以獲得這份信息。
這種重構(gòu)的最簡(jiǎn)單情況就是:臨時(shí)變量只被賦值一次狸吞,或者賦值給臨時(shí)變量的表達(dá)式不受其他條件影響
做法:
(1)找出只被賦值一次的臨時(shí)變量
(2)將該臨時(shí)變量聲明為final
(3)編譯(確保該臨時(shí)變量的確只被賦值一次)
(4)將“對(duì)該臨時(shí)變量賦值”的語(yǔ)句的等號(hào)右側(cè)部分提煉到一個(gè)獨(dú)立函數(shù)中
(5)編譯勉耀,測(cè)試
(6)在該臨時(shí)變量身上實(shí)施Inline Temp(P119)
范例:
示例函數(shù)
double getPrice(){
int basePrice=_quantity*_itemPrice;
double discountFactor;
if(basePrice>1000)
discountFactor=0.95;
else
discountFactor=0.98;
return basePrice*discountFactor;
}
聲明為final
double getPrice(){
final int basePrice=_quantity*_itemPrice;
final double discountFactor;
if(basePrice>1000)
discountFactor=0.95;
else
discountFactor=0.98;
return basePrice*discountFactor;
}
替換臨時(shí)變量
double getPrice(){
final int basePrice=basePrice();
final double discountFactor;
if(basePrice>1000)
discountFactor=0.95;
else
discountFactor=0.98;
return basePrice*discountFactor;
}
private int basePrice(){
return _quantity*_itemPrice;
}
使用Inline Temp
double getPrice(){
final int basePrice=basePrice();
final double discountFactor;
if(basePrice()>1000)
discountFactor=0.95;
else
discountFactor=0.98;
return basePrice*discountFactor;
}
private int basePrice(){
return _quantity*_itemPrice;
}
替換其他臨時(shí)變量,刪掉臨時(shí)變量
double getPrice(){
//final int basePrice=basePrice();
final double discountFactor;
if(basePrice()>1000)
discountFactor=0.95;
else
discountFactor=0.98;
return basePrice()*discountFactor;
}
private int basePrice(){
return _quantity*_itemPrice;
}
提煉discountFactor()
double getPrice(){
final double discountFactor=discountFactory();
return basePrice()*discountFactor;
}
private int basePrice(){
return _quantity*_itemPrice;
}
private double discountFactor(){
if(basePrice()>1000)
reurn 0.95;
else
return 0.98;
}
最終重構(gòu)函數(shù)getPrice()
double getPrice(){
return basePrice()*discountFactor();
}
private int basePrice(){
return _quantity*_itemPrice;
}
private double discountFactor(){
if(basePrice()>1000)
reurn 0.95;
else
return 0.98;
}
在實(shí)際的開發(fā)過程中蹋偏,如果能一眼就能發(fā)現(xiàn)的簡(jiǎn)單的可替換的臨時(shí)變量便斥,不妨動(dòng)手試試!
重構(gòu)之后威始,發(fā)現(xiàn)代碼行數(shù)變多了枢纠,方法增加了,但是整體看上去黎棠,發(fā)現(xiàn)邏輯清楚了晋渺。