當抽象未被充分分解——進一步拆解可降低其大小或實作複雜度——就出現 Insufficient Modularization。

核心定義#

兩種形態(也常合併出現):

  • 臃腫介面(bloated interface):公開介面包含過多成員。
  • 臃腫實作(bloated implementation):方法過多,或方法本身複雜度過高。

「操作與類別應有和諧的大小,避免兩端的極端。」—— Lanza & Marinescu

與 Multifaceted Abstraction 的差別#

壞味道違反的原則焦點
Multifaceted Abstraction(3.4)SRP(單一職責)一個抽象多個責任
Insufficient Modularization分解原則一個抽象過大、過於複雜

兩者經常同時出現,但並不等同。

  • 一個抽象可以只有一個責任,但實作很龐大
  • 一個抽象也可以很小,但承擔多個責任

常見成因#

  • 集中式控制:把大量工作集中到單一抽象或方法。
  • 為「滿足多個客戶端」而做大:以為大型抽象可滿足所有客戶,反而拖垮可變更性。
  • 把所有相關功能塞在一起:對 SRP 認知不深的開發者常如此。

範例#

範例 1:java.net.SocketPermission(臃腫實作)#

JDK 1.7 的 SocketPermission

  • 各方法 Cyclomatic complexity 總和為 193
  • 私有方法 getMask() 單一方法的 Cyclomatic complexity 達 81——巢狀條件、迴圈混雜。

範例 2:java.awt.Component(臃腫介面 + 臃腫實作)#

java.awt.Component

  • 332 個方法(259 個 public)
  • 107 個欄位
  • 11 個內部類別
  • 10,102 行程式碼
  • 所有方法 Cyclomatic complexity 總和為 1143
  • dispatchEventImpl(Event) 單一方法的 Cyclomatic complexity 為 65

Figure 5.8: java.awt.Component 類別龐大且密集

JDK 7 中其他例子:

  • javax.swing.JTable:44 欄位、203 方法、9608 行程式碼
  • java.lang.BigInteger:28 欄位、103 方法
  • java.util.Calendar:81 欄位、71 方法

Figure 5.9: java.swing.JTable 類別龐大且密集

軼事:流程黏滯逼出的 40,000 行類別#

跨國醫療軟體專案中,新加類別必須由總部團隊核可,流程冗長。在交期壓力下,外包團隊不再新建類別——所有新功能塞進既有類別。其中一個類別最終 40,000 行、WMC(方法 Cyclomatic complexity 總和)超過 2000。

兩個關鍵教訓:

  • 流程若不友善,人就會繞過它——流程設計者必須讓正確的事容易做。
  • 管理層不見得意識到流程對技術債的影響——應主動衡量並調整。

建議重構#

臃腫介面#

  • 找出公開介面中的內聚子集,抽取為獨立抽象
  • 一個類別有多組各自內聚的成員 → 拆成多個類別。
  • 介面為多個客戶端服務時,套用 Interface Segregation Principle (ISP),拆成多個客戶導向的介面。

臃腫實作#

  • 複雜方法 → 抽取私有 helper 方法以化簡。
  • 同時有 Multifaceted Abstraction → 把每個責任封裝到不同類別。

範例 1 的具體重構#

  • 把空白略過、字串比對等步驟抽出 matchForKnownStrings() 等 helper 方法。
  • 原本對 CONNECTRESOLVELISTENACCEPT 重複了四次的字元比對邏輯,改為呼叫該 helper 四次。

範例 2 的具體重構#

Component 類別涉及事件監聽、版面定位、焦點、字型、圖形設定等多個關注點。建議:

  • 把事件監聽抽為 ComponentEvents 介面,搭配 DefaultComponentEvents 預設實作;Component 透過委派使用。
  • getFontMetrics()createImage()createVolatileImage() 移到 FontMetricsImageVolatileImage

對品質屬性的衝擊#

  • 理解性:臃腫介面難理解;臃腫實作難維護。
  • 可變更性與可擴充性:客戶端依賴此介面 → 改動波及廣;實作大 → 難找該動哪。
  • 可測試性:高 Cyclomatic complexity → 路徑數爆增 → 測試案例數同步爆增。
  • 可靠性:複雜度本身就是 bug 的溫床。

別名#

  • God class:類別有 50 個以上方法或屬性。
  • Fat interface:類別介面不內聚。
  • Blob class:類別非常大且複雜度高。
  • Classes with complex control flow:類別整體 Cyclomatic complexity 過高。
  • Too much responsibility:類別責任過重。
  • Local breakable (class):類別責任過重且本地相依過多。

實務考量#

核心類別(key classes)#

系統中最重要的概念對應的類別常天生大、複雜、被許多類別倚賴。即使如此,仍應思考如何分解,使其便於維護。

自動產生的程式碼#

解析器產生工具(parser generator)等通常輸出含大量條件邏輯的複雜程式碼。修改 generator 或手工重構此類程式碼,實務上極難