《重構(gòu)-改善既有代碼的設(shè)計》筆記-代碼的壞味道(下)

平行繼承體系(parallel Inheritsnce hierarchies)

是Shotgun surgery的特殊情況,每當(dāng)為某一個類增加一個子類,必須為另一個類增加子類,如果發(fā)現(xiàn)某個繼承體系的類名前綴和另一個繼承體系的類名前綴完全相同,就聞到了壞味道。
解決方案:讓一個繼承體系的實(shí)例引用另一個繼承體系的實(shí)例,再使用move method 和,move field,將引用端的繼承體系消弭于無形

冗贅類(Lazy Class)

如果有一個類的所得不值其身價,就應(yīng)該消失,比如某個類原本對得起它自己的價值,但是重構(gòu)使它身形縮水,不再做那么多工作,或者開發(fā)前規(guī)劃了某些變化,添加一個類來應(yīng)對變化,但實(shí)際上沒有發(fā)生這種變化。如果子類沒有做足夠的工作,試試Collapse hierarchy,對于沒有用的組件,用Inline Class進(jìn)行處理

夸夸其談未來性(Sepculative Generality)

想到一些情況,覺得總有一天需要做這個事情,然后企圖以各式各樣的鉤子和特殊情況來處理一些非必要的事情,形成壞味道,這樣會造成系統(tǒng)更難理解和維護(hù),用不上的配置應(yīng)搬開。如果都能用上,那這么做就是值得的。如果函數(shù)或類的唯一用戶是測試用例,請先確認(rèn)它們的用途是否幫主測試用例檢測正當(dāng)功能,如果不是,請連同測試用例一并刪掉。

令人迷惑的暫時字段(Tempoary Field)

如果某個實(shí)例變量僅為某種特定情況而設(shè),請使用Extract class把所有和這個變量相關(guān)的代碼都放到一個新類里面,還可以用 introduce null object在變量不合法的情況下創(chuàng)造一個null 對象,從而避免寫出條件式代碼
如果一個復(fù)雜需要好幾個變量,可以利用Extract class 把這些變量和相關(guān)函數(shù)提煉到一個獨(dú)立類中。

過度耦合的消息鏈(Message Chains)

如果看到用戶向一個對象請求另一個對象,然后再向后者請求另一個對象,然后再再請求另一個對象。。。這就是消息鏈。這樣客戶代碼將與查找過程中的導(dǎo)航機(jī)構(gòu)緊密耦合,一旦對象間的關(guān)系發(fā)生任何變化,客戶端就不得不做出相應(yīng)修改
解決方案:先觀察消息鏈最終得到的對象是用來干什么的,看看能否以Extract method把使用該對象的代碼提煉到一個獨(dú)立函數(shù)中,再運(yùn)用move medthod 把這個函數(shù)推入消息鏈。

中間人(middle man)

對象的基本特征之一就是封裝--對外部世界隱藏其內(nèi)部細(xì)節(jié),封裝往往伴隨著委托。如果一個類接口有一半的函數(shù)都委托給其他類,這就是過度委托,這時應(yīng)該使用remove middle man,直接和真正負(fù)責(zé)的對象打交道。

狎昵關(guān)系(inappropriate intimacy)

如果兩個過于親密,可以采用move medthod 和move field幫他們劃清界限,減少狎昵行徑。也可以用change bidirectional association to unidirection 讓其中一個類對另一個類斬斷情絲,也可以用hide delegate讓另一個類來為他們傳遞相思情。如果需要讓子類獨(dú)立,可使用replace inheritance with delegation

異曲同工的類(alternative class with different interfaces)

如果兩個函數(shù)做著同一件事,卻有著不同的簽名,請運(yùn)用rename method根據(jù)它們用途重新命名,然后反復(fù)運(yùn)用move method 將某些行為移入類,直到兩者協(xié)議一致為止。

不完整的庫類(incomplete library class)

如果只修改庫類的一兩個函數(shù),可以運(yùn)用introduce foreign method
如果想要添加一大推額外行為,就得運(yùn)用introduce local extension

純稚的數(shù)據(jù)類(data class)

data class 指它們擁有一些字段,以及用于訪問(讀寫)這些字段的函數(shù),是一種不會說話的數(shù)據(jù)容器
public字段應(yīng)使用encapsulate field封裝起來
容器類字段應(yīng)使用encapsulate collection 封裝起來
不被其他類修改的字段,應(yīng)運(yùn)用remove setting method

被拒絕的遺贈(redused bequest)

過多的注釋(comments)

過多的注釋以為這代碼很糟糕,我們需要利用各種重構(gòu)收費(fèi)把壞味道去除
如果需要用注釋來解釋代碼做了什么,用extract method
如果函數(shù)已經(jīng)提取出來,需要用注釋來解釋行為,用rename method
如果注釋是說明某些系統(tǒng)的需求規(guī)格,用intrduce assertion

當(dāng)你感覺需要撰寫注釋時,請先嘗試重構(gòu),試著讓左右注釋都變得多余

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容