核心思想:拆細(xì)厦画、公用
重構(gòu)可以是修改變量名嘱能、重新安排目錄這樣簡(jiǎn)單的物理重構(gòu),也可以是抽取子函數(shù)伦吠、精簡(jiǎn)冗余設(shè)計(jì)這樣稍許復(fù)雜的邏輯重構(gòu)妆兑。但均不改變現(xiàn)有代碼的功能。
了解敵人——丑陋的代碼
臃腫的類
開發(fā)者缺乏對(duì)最基本的編碼原則毛仪,即“單一職責(zé)原則”(SRP)的理解搁嗓。開發(fā)者不去思考這些功能是不是應(yīng)該放在這同一個(gè)類中,導(dǎo)致這些類會(huì)變得很臃腫箱靴,造成一個(gè)類幾千行腺逛,讓下一個(gè)接盤俠欲哭無淚。臃腫的方法
好幾十上百行的一個(gè)函數(shù)堆在一塊衡怀,用面向過程的思想來寫代碼棍矛。函數(shù)參數(shù)過多
函數(shù)參數(shù)過多會(huì)導(dǎo)致調(diào)用者對(duì)方法難以理解,參數(shù)弄混抛杨。想象一下一個(gè)函數(shù)連續(xù)傳5個(gè)int值參數(shù)够委,能分清誰是誰嗎?建議可以將參數(shù)組成一個(gè)對(duì)象傳入。層層嵌套的判斷
如果邏輯不復(fù)雜盡量減少if-else的分支包裹怖现,他人太難閱讀慨绳。比如不滿足條件了直接return,不走其他代碼真竖,這樣可以減少一層嵌套脐雪。滿篇跑的常量值
一個(gè)類里面出現(xiàn)各種未命名的常量值。0恢共,1战秋,200等等鋪天蓋地。這種狀態(tài)碼意義改了讨韭,改代碼會(huì)把你改哭的脂信。難道就不能先聲明一個(gè)統(tǒng)一的常量變量來使用嗎癣蟋。模棱兩可的命名
不能根據(jù)名字一眼看懂它的功能的命名不是一個(gè)好命名。當(dāng)然生僻的單詞除外狰闪。模糊的疯搅,沒有功能意義的命名會(huì)給閱讀造成很大困難。
重構(gòu)之道
分拆大函數(shù): Break Method
當(dāng)函數(shù)比較大了埋泵,就可以根據(jù)功能節(jié)點(diǎn)分拆成多個(gè)小函數(shù)幔欧,也許其中的小函數(shù)還可以公用。比如結(jié)算購物車丽声,包括計(jì)算各類商品的總價(jià)礁蔗,再計(jì)算折扣,再計(jì)算滿減優(yōu)惠雁社,如果一個(gè)方法執(zhí)行完浴井,那么別人要只要邏輯就要從頭到尾讀一遍。而分別拆分成三個(gè)霉撵,一眼就能看出這段邏輯先后做了什么磺浙。寫方法切忌一口吃一個(gè)胖子。封裝到父類:
如果多各類要執(zhí)行相似的功能和代碼徒坡,可以把該方法放到它們的父類中屠缭,或者提取出來成業(yè)務(wù)工具類。Move Method----方法遷移
遵守“單一職責(zé)”原則崭参,當(dāng)類中的方法不適合放在當(dāng)前類中時(shí)呵曹,就應(yīng)該為該方法尋找合適下家。移到與方法耦合大的類中何暮。當(dāng)一個(gè)方法被其他類使用比在它所在類中的使用還要頻繁時(shí)奄喂,我們就需要使用遷移方法重構(gòu)了——將方法遷移到更頻繁地使用它的類中。Move Field----搬移字段
當(dāng)在一個(gè)類中的某一個(gè)字段海洼,被另一個(gè)類的對(duì)象頻繁使用時(shí)跨新,我們就應(yīng)該考慮將這個(gè)字段的位置進(jìn)行更改了Extract Class----提煉類
一個(gè)類如果過于復(fù)雜,做了好多的事情坏逢,違背了“單一職責(zé)”的原則域帐,所以需要將其可以獨(dú)立的模塊進(jìn)行拆分,當(dāng)然有可能由一個(gè)類拆分出多個(gè)類是整。
對(duì)類的細(xì)化也是為了減少代碼的重復(fù)性肖揣,以及提高代碼的復(fù)用性,便于代碼的維護(hù)浮入。提升方法龙优、字段(Pull Up Method)
將方法向繼承鏈上層遷移的過程。用于一個(gè)方法被多個(gè)實(shí)現(xiàn)者使用時(shí)事秀。在繼承的體系中彤断,當(dāng)多個(gè)類使用了相同或類似的方法野舶,就可以考慮將該方法抽取到基類,沒有基類就創(chuàng)建一個(gè)宰衙。字段提升同方法平道。降低方法
即父類抽象方法讓多個(gè)子類實(shí)現(xiàn)。多個(gè)子類有相同的功能但是有各個(gè)具體的實(shí)現(xiàn)方法供炼,那么這種封裝就可以用多態(tài)性了一屋,父類創(chuàng)建一個(gè)抽象方法,將方法實(shí)現(xiàn)降低到子類劲蜻。重復(fù)代碼的提煉
有時(shí)候?yàn)榱粟s項(xiàng)目進(jìn)度陆淀,盡快完成功能考余,會(huì)偷懶將實(shí)現(xiàn)功能的一片代碼復(fù)制一遍先嬉,直接套用。這種把多余的刪掉楚堤,保留一個(gè)疫蔓,也許只需傳一兩個(gè)參數(shù)就可以封成一個(gè)方法供多處調(diào)用。重命名變量(類身冬、方法衅胀、變量)
這個(gè)很重要,可以不夸張地說酥筝,命名的水平就體現(xiàn)了編程能力的高低滚躯。在重構(gòu)的過程中,當(dāng)發(fā)現(xiàn)類名嘿歌,方法名在當(dāng)前版本不符合它的功能含義掸掏,就該考慮對(duì)其重新命名。補(bǔ)加注釋
對(duì)于全局變量宙帝,公用函數(shù)丧凤,邏輯復(fù)雜的地方添加注釋,彌補(bǔ)之前的遺漏步脓。將較長的判斷或代碼運(yùn)算用臨時(shí)變臉暫存
if(stateCode = OK && datas != null && canShow)
function(Math.random((num1-num2)*num3))
如上這種長長的判斷條件和參數(shù)會(huì)使 這種代碼應(yīng)該先將if判斷條件寫成一個(gè)變量愿待,放入變量判斷,將function參數(shù)寫一個(gè)局部變量保存結(jié)果靴患,再傳入方法仍侥。
使用泛型封裝成統(tǒng)一的方法或類
函數(shù)要避免過多的參數(shù)造成閱讀的復(fù)雜性
public void requestPhoneThirdRegister(String loginway, String nickname, String openId, String token, String expires, String phone, final CallBackimpl callBackimpl)
用這樣的方法直接傳參數(shù)就太長了,嚴(yán)重降低代碼可讀性鸳君。我們可以將參數(shù)變量寫到一個(gè)實(shí)體類中访圃,通過構(gòu)造方法初始化對(duì)象屬性值,只需要傳遞一個(gè)對(duì)象就搞定相嵌,也解決了增減參數(shù)帶來的變動(dòng)問題腿时。
- 嵌套條件分支優(yōu)化
if(){
if(){
if(){
}
}
}else{
}
相信大家也見識(shí)過不少這樣的箭頭代碼况脆,像怎么也解不開的死結(jié)。遇到這種代碼批糟,一定要盡可能要優(yōu)化格了。通常做法:判斷語句,if條件成立徽鼎,執(zhí)行代碼塊盛末,誒,這樣就生成了一個(gè)嵌套層級(jí)否淤。
優(yōu)化的核心思想:直接判斷不滿足的條件悄但,if條件成立,直接return石抡,盡快跳出方法來減少嵌套的層級(jí)檐嚣。
第二種:將條件判讀合并
- 盡量避免雙重否定的條件
private boolean isChecked(){
if(){
return true;
}
}
一個(gè)條件方法。
if(!isChecked()){
}
然后用否定來判斷這個(gè)條件啰扛,這樣可能會(huì)一時(shí)之間轉(zhuǎn)變不過來導(dǎo)致條件判斷反了嚎京。當(dāng)然頭腦靈活的忽略這條。
去除東北亂燉的Util類
當(dāng)我們?cè)趯懘a中偶然間需要抽出公用方法時(shí)隐解,一時(shí)之間找不到合適的類去放置鞍帝,然后就隨意地放進(jìn)了XXUtil或XXManager類中。長此以往煞茫,該類所含功能越來越雜帕涌,dp和px轉(zhuǎn)化在其中,屏幕尺寸相關(guān)方法在其中续徽,日期轉(zhuǎn)化在其中蚓曼,加密的索性也放在其中,那有無網(wǎng)絡(luò)炸宵,網(wǎng)絡(luò)類型判斷也加入吧辟躏。這不就像垃圾場(chǎng)了嗎,各類雜物都堆在其中土全,不符合單一職責(zé)原則捎琐,應(yīng)該按照如上的功能塊分解成多個(gè)職責(zé)單一的類。類多不要緊裹匙,關(guān)鍵要做到職責(zé)單一瑞凑。將滿篇跑的魔鬼數(shù)字和字符串用定義的常量表示。
如果只是某個(gè)類或者某個(gè)模塊需要用到該常量概页,就聲明到對(duì)應(yīng)類中籽御。如果是全局項(xiàng)目都會(huì)用到的常量,就提升到項(xiàng)目的常量配置文件中。