重讀《重構(gòu)》中的24種代碼「壞味道」

前言:本文只摘要了24種代碼「壞味道」最核心的要點(diǎn),也不準(zhǔn)備貼代碼示例,是因?yàn)镾heldon自己在寫的過程中,自然就想起了很多自己寫的代碼「壞味道」。所以希望大家在看文章的過程中多回憶自己的代碼,而不是被冗長的文字和大量代碼示例分散注意力。

1. 神秘命名

命名是編程中最難的兩件事之一。正因?yàn)槿绱?,修改命名可能是最常用的重?gòu)方法。

如果你發(fā)現(xiàn)改名很難,那就說明代碼設(shè)計(jì)有問題。

當(dāng)我們不能給一個(gè)模塊,一個(gè)對(duì)象,一個(gè)函數(shù),甚至一個(gè)變量找到合適名稱的時(shí)候,往往說明我們對(duì)問題的理解還不夠透徹,需要重新去挖掘問題的本質(zhì),對(duì)問題域進(jìn)行重新分析和抽象。

2. 重復(fù)代碼

同一類的兩個(gè)函數(shù)含有相同的表達(dá)式,就應(yīng)該提煉。

3. 過長函數(shù)

活得最長,最好的程序,其中函數(shù)一般都很短。

如果你覺得需要寫注釋,大部分情況就代表這個(gè)東西需要寫進(jìn)一個(gè)獨(dú)立的函數(shù)里面,然后根據(jù)用途來命名比較好。
條件表達(dá)式和循環(huán)往往也是提煉函數(shù)的信號(hào)。

4. 過長參數(shù)列表

使用類可以有效的縮短參數(shù)列表。如果多個(gè)函數(shù)有同樣的幾個(gè)參數(shù),引入一個(gè)類就尤為有意義。

5. 全局?jǐn)?shù)據(jù)

全局?jǐn)?shù)據(jù)仍然是最刺鼻的壞味道之一。它的問題是,全局?jǐn)?shù)據(jù)在任何地方都可以被修改。

所以正確的做法是將全局?jǐn)?shù)據(jù)封裝起來,用函數(shù)將其包起來,這樣就知道那些地方修改了它。

有少量的全局?jǐn)?shù)據(jù)或者無妨,但數(shù)量越多,處理難度就會(huì)指數(shù)上升。(良藥與毒藥的區(qū)別在于劑量)

6. 可變數(shù)據(jù)

核心是縮小作用域。

可以通過封裝變量來確保所有數(shù)據(jù)更新操作都通過很少幾個(gè)函數(shù)來進(jìn)行,使其更容易被監(jiān)控。

7. 發(fā)散式變化

發(fā)散式變化指某個(gè)模塊因?yàn)椴煌脑蛟诓煌姆较蛏习l(fā)生變化。

每次只關(guān)心一個(gè)上下文。

找到引起發(fā)散式變化的原因,將它拆分出來。

8. 霰彈式修改

在每次修改的時(shí)候,應(yīng)該只修改一處,而不是到處的修改。因?yàn)橐粋€(gè)需求,需要修改3處代碼,那么這就需要思考,這3處代碼是否應(yīng)該抽離出來。

一個(gè)常用的策略就是使用內(nèi)聯(lián)(inline)重構(gòu)代碼把本不該分散的邏輯拽回一處。

9. 依戀情結(jié)

模塊化,力求代碼分出區(qū)域,最大化區(qū)域內(nèi)部交互,最小化區(qū)域間交互。

如果兩個(gè)模塊交互頻繁,它們應(yīng)該合并在一起。

10. 數(shù)據(jù)泥團(tuán)

如果在多個(gè)類中,出現(xiàn)了很多相同項(xiàng)的數(shù)據(jù),你需要想想是否要通過將數(shù)據(jù)提煉成類,來抽離出一個(gè)獨(dú)立對(duì)象。

建議新建類而非簡單的結(jié)構(gòu)體。

11. 基本類型偏執(zhí)

很多程序員不愿意創(chuàng)建對(duì)自己的問題域有用的基本類型,如錢,坐標(biāo),范圍等。

比如有程序員用字符串來表示電話號(hào)碼,實(shí)際上你應(yīng)該抽象出來一個(gè)電話號(hào)碼對(duì)象。

12. 重復(fù)的switch

盡量使用多態(tài)而非switch。

13. 循環(huán)語句

我們應(yīng)該用管道操作(如filter和map)來替代循環(huán),這樣能更快的看清被處理的元素和處理他們的動(dòng)作。

14. 冗贅的元素

能簡單的代碼,盡量簡單。未來變復(fù)雜的時(shí)候,再去考慮它。

15. 夸夸其談的通用性

同上,能簡單的代碼,盡量簡單。通用性?過早的優(yōu)化是萬惡之源

16. 臨時(shí)字段

臨時(shí)字段指內(nèi)部某個(gè)字段僅為某種特定情況而設(shè)。

臨時(shí)的字段不應(yīng)該存在。你需要給他們搬個(gè)新家,把所有和臨時(shí)變量相關(guān)的代碼搬至那里。

17. 過長的消息鏈

如果你看到用戶向一個(gè)對(duì)象請(qǐng)求另一個(gè)對(duì)象,然后再向后者請(qǐng)求另一個(gè)對(duì)象,然后再請(qǐng)求另一個(gè)對(duì)象,這就是消息鏈。

消息鏈意味著客戶端會(huì)耦合消息鏈的查找過程。應(yīng)該將查找過程獨(dú)立出一個(gè)函數(shù)。

18. 中間人

委托函數(shù)過多時(shí),減少委托,移除中間人,讓調(diào)用者直接訪問目標(biāo)類進(jìn)行操作。

19. 內(nèi)幕交易

減少模塊之間頻繁的數(shù)據(jù)交換,并把這種交換放到明面上。

20. 過大的類

當(dāng)一個(gè)類代碼行數(shù)太多或者功能職責(zé)太多的時(shí)候,拆掉它。

兩種拆分方法:

提取新類,當(dāng)大類的部分行為可以分解為一個(gè)單獨(dú)的組件,則可以使用提取類的方式拆分。
提取子類,當(dāng)大類的部分行為可以以不同的方式實(shí)現(xiàn)或在極少數(shù)情況下使用,則可以使用提取子類方式拆分。

21. 異曲同工的類

兩個(gè)類有著相同的功能,但方法名稱不同。

重命名方法,并去除掉不必要的重復(fù)代碼。

22. 純數(shù)據(jù)類

純數(shù)據(jù)類常常意味著行為被放在了錯(cuò)誤的地方。處理數(shù)據(jù)的行為應(yīng)該從客戶端移至純數(shù)據(jù)類中。

23. 被拒絕的遺贈(zèng)

如果子類復(fù)用了父類的實(shí)現(xiàn),就應(yīng)該支持父類的接口。

24. 注釋

注釋是提示你,這個(gè)地方該重構(gòu)啦。

如果你覺得需要寫注釋的時(shí)候,請(qǐng)先重構(gòu),試著讓所有注釋都變得多余。

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

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

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