代碼異味是系統潛在問題的表徵,亦是重構的主要目標。本文列舉 Martin Fowler《重構》經典 21 種代碼異味前半段,附帶成因分析與應對策略,助力開發者建立代碼質量敏銳度。
最常見異味,源於複製貼上編程風格。對應原則:OAOO(Once And Only Once)。重構手法:提煉方法、提煉類、上拉/下拉方法。
結構化編程遺毒。方法應單一意圖。重構:提煉方法、引入參數對象、以方法對象取代方法。
承擔過多職責。原則:一類一職責。重構:提煉類、提煉超類/介面。
單一類因不同原因頻繁變更(如某字段每小時變、某字段每年變)。重構:提煉類隔離變化維度,使穩定部分可復用。
與發散式變化相反:一處變更引發多處連鎖修改。重構:將共同變化的字段/方法聚合到同一類。
方法頻繁訪問其他類字段(大量 getter)。重構:將行為移至數據最豐富的類(移動方法)。
多組數據總一起出現(字段、參數列表)。重構:提煉為獨立值物件/類。
用基本類型組合表達領域概念(如兩個 int 表達範圍、float 表達金額)。重構:以小物件封裝領域概念(Range、Money、Percentage、ZipCode)。
基於常量的 switch 是 OO 大敵。重構:以多態(子類/狀態/策略模式)取代條件分支。
霰彈式修改特例:修改一體系類必須同步修改另一體系平行子類。重構:合併體系或引入委託。
承擔極少職責,維護成本大於價值。重構:內聯類、合併類。
實現從未用到的功能/通用性(唯一用戶是測試用例)。重構:果斷刪除(YAGNI 原則)。
字段僅特定情況下有意義(如特定演算法變量)。重構:提煉類封裝相關字段與行為。
客戶調用 A 獲取 B,再調用 B 獲取 C... 重構:隱藏委託、引入中介者。
類大部分方法僅委託他類。封裝不等於無限制委託。重構:移除中間人、直接調用目標。
類間過度訪問彼此私有細節。重構:移動方法/字段、改用介面、引入中介者。
功能相似的類卻有不同介面。重構:統一介面、提煉超類/介面、適配器模式。
這 17 種異味(原文 21 種,文中截斷)構成代碼質量診斷清單。識別異味非為指責,而是為適時重構創造契機。建議團隊建立 Code Review 異味檢查清單,將《重構》目錄內化為肌肉記憶。
(註:原文第 17 條後截斷,完整 21 種異味尚包括:拒絕繼承、註釋、臨時字段等,請參考《重構》原著第 3 章。)