重復(fù)代碼(Duplicated Code)
1>同一個(gè)類(lèi)的兩個(gè)函數(shù)含有相同的表達(dá)式
解決方法:采用Extract Method提煉出重復(fù)的代碼,然后讓兩個(gè)地點(diǎn)都調(diào)用被提煉出來(lái)的那一段
2>兩個(gè)互為兄弟的子類(lèi)內(nèi)含相同表達(dá)式
解決方法:只需對(duì)兩個(gè)雷都使用Extract Methid,然后再對(duì)被提煉出來(lái)的代碼使用Pull Up Medthod,將它推入超類(lèi)
3>代碼只是類(lèi)似,并非完全相同
解決方法:運(yùn)用Extract Method將相似部分和差異部分分隔開(kāi),構(gòu)成單獨(dú)一個(gè)函數(shù),然后可能可以運(yùn)用Form Template Method 獲一個(gè)Template Medthod設(shè)計(jì)模式
4>兩個(gè)毫不相關(guān)的類(lèi)出現(xiàn)相同代碼
解決方法:考慮對(duì)其中一個(gè)使用Extract Class,將充分代碼提煉到一個(gè)獨(dú)立勒種,然后在另一個(gè)類(lèi)使用這個(gè)新類(lèi)
過(guò)長(zhǎng)函數(shù)(Long Method)
程序越長(zhǎng)約難理解,而間接層能帶來(lái)利益:解釋能力,共享能力,選擇能力,這些能力都是由小型函數(shù)支持。小函數(shù)容易理解的真正關(guān)鍵在于一個(gè)好名字。我們積極的分解函數(shù),應(yīng)遵循這樣一條原則:每當(dāng)感覺(jué)需要以注釋來(lái)說(shuō)么點(diǎn)什么的時(shí)候,就需要把需要說(shuō)明的東西寫(xiě)進(jìn)一個(gè)獨(dú)立函數(shù)中,并以其用途命名。
1>把函數(shù)變小,只需要使用Extract Method
2>提取函數(shù)時(shí),參數(shù)和臨時(shí)變量過(guò)多,可以運(yùn)用Replace Temp With Query,Introduce Parameter Object和Preserve Whole Object可以將參數(shù)列變的更簡(jiǎn)潔一些
3>如何確定該提煉哪一段代碼
- 尋找注釋。如果代碼前方有一行注釋?zhuān)褪窃谔嵝涯?,可以將代碼替換成函數(shù)
- 條件表達(dá)式和循環(huán)常常也是提煉的信號(hào),可以使用Decompose Conditional處理?xiàng)l件表達(dá)式。至于循環(huán),應(yīng)當(dāng)將循環(huán)和其內(nèi)的代碼提煉到一個(gè)獨(dú)立函數(shù)中
過(guò)大的類(lèi)(Large Class)
1>太多實(shí)例變量
解決辦法:運(yùn)用Extract Class 將幾個(gè)變量一起提煉至新類(lèi)內(nèi),提煉時(shí)應(yīng)選擇類(lèi)內(nèi)批次相關(guān)的變量。如果類(lèi)內(nèi)的數(shù)個(gè)變量有著相同的前綴或字尾,就可以考了將他們提煉到某一個(gè)組件內(nèi)。如果組件適合作為子類(lèi),使用Extract Subclass比較簡(jiǎn)單
2>太多代碼
解決方法:先確定客戶(hù)端如何使用它們,然后運(yùn)用Extract Interface的每一種使用方式提煉出一個(gè)接口,這樣幫助我們看清楚如何分解類(lèi)
3>是個(gè)GUI類(lèi)
解決方法:需要把數(shù)據(jù)和行為移到一個(gè)獨(dú)立的領(lǐng)域?qū)ο笕ァ?/p>
過(guò)長(zhǎng)參數(shù)列(Long Paramter List)
如果向已有的對(duì)象發(fā)出一條請(qǐng)求就可以取代一個(gè)參數(shù)。那么你應(yīng)該激活重構(gòu)手法Replace Paramter With Method。在這里“已有的對(duì)象”可能是函數(shù)所屬類(lèi)內(nèi)的一個(gè)字段,也可能是另一個(gè)參數(shù)。還可以運(yùn)用Preserve Whole Object 將來(lái)自同一對(duì)象的一堆數(shù)據(jù)收集起來(lái),并以該對(duì)象替換它們。如果某些數(shù)據(jù)缺乏合理的對(duì)象歸屬,可以使用Introduce paramter Object 為它們制造出一個(gè)參數(shù)對(duì)象。
發(fā)散式變化(Divergent Change)
針對(duì)某一外界變化的所有相應(yīng)修改,都只應(yīng)該發(fā)生在單一類(lèi)中,而這個(gè)新類(lèi)的所有內(nèi)容都應(yīng)該反應(yīng)此變化。為此,找出某特定原因而造成的所有變化,然后運(yùn)用Extract Class將它們到另一個(gè)類(lèi)中。
霰彈式修改(Shotgun Surgery)
1>每遇到某種變化,都必須在許多不同的類(lèi)內(nèi)做出許多小修改。
解決方法:使用Move Method 和Move Field把所有需要修改的代碼放進(jìn)同一類(lèi),如果沒(méi)有合適的類(lèi)可以安置代碼,就創(chuàng)造一個(gè)。通??梢赃\(yùn)用Inline Class把一系列相關(guān)行為放進(jìn)同一個(gè)類(lèi)。
divergent Change是指“一個(gè)類(lèi)受多種變化的影響”,而Shotgun Surgery則指“一種變化引發(fā)多個(gè)類(lèi)相應(yīng)修改”。
依戀情節(jié)(Feature Envy)
某函數(shù)為了計(jì)算某個(gè)值,從另一個(gè)對(duì)象那里調(diào)用幾乎半打的取值函數(shù)。
解決方法:用move method把這個(gè)函數(shù)移到另一個(gè)地點(diǎn)
如果一個(gè)函數(shù)用到幾個(gè)類(lèi)的功能,那么要移到哪里?判斷哪個(gè)類(lèi)擁有最多被此函數(shù)使用的函數(shù),就把這個(gè)函數(shù)和那些數(shù)據(jù)擺在一起。最根本的原則:將總是一起變化的東西放在一塊,數(shù)據(jù)和引用這些數(shù)據(jù)的行為總是一起變化的
數(shù)據(jù)泥團(tuán)(Data Clumps)
兩個(gè)類(lèi)中相同的字段,許多函數(shù)簽名中相同參數(shù)。這些總是綁在一起出現(xiàn)的數(shù)據(jù)真應(yīng)該擁有屬于它們自己的對(duì)象。首先找出這些數(shù)據(jù)以字段形式出現(xiàn)的地方,運(yùn)用Introduce Paramter Object 或者 Preserve Whole Object 為他減肥。這么做的直接好處是可以將很多參數(shù)列縮短,簡(jiǎn)化函數(shù)調(diào)用。
基本類(lèi)型偏執(zhí)(Primitive Obsession)
編程環(huán)境中有兩種數(shù)據(jù):結(jié)構(gòu)類(lèi)型和基本類(lèi)型。對(duì)象的一個(gè)極大的價(jià)值在于,它們模糊了橫亙于基本數(shù)據(jù)和體積較大的類(lèi)的界限。
對(duì)象新手通常不愿意在小任務(wù)上運(yùn)用小對(duì)象,像結(jié)合數(shù)值和幣種的money類(lèi),由一個(gè)起始值和一個(gè)結(jié)束值組成的range類(lèi)。可以運(yùn)用replace dats value with object將原本單獨(dú)存在的數(shù)值替換為對(duì)象。如果想要替換的數(shù)據(jù)值是類(lèi)型碼,可以運(yùn)用replace type code with class將它替換。如果有與類(lèi)型碼相關(guān)的條件表達(dá)式,可以運(yùn)用 replace type code with subclass 或 replace type code with state/strategy 處理
Switch驚悚現(xiàn)身(Switch Statement)
Swith應(yīng)考慮用多態(tài)來(lái)替換
先用Extract method 將switch語(yǔ)句提煉到一個(gè)單獨(dú)函數(shù),再以move method 將它移到需要多態(tài)性的那個(gè)類(lèi),此時(shí)需決定是否用 replace type code with subclass 或 replace type code with state/strategy ,完成繼承結(jié)構(gòu)以后,可以運(yùn)用replace conditional with polymorphism