當原本應該集中在同一抽象的資料與方法被散落到多個抽象時,就出現 Broken Modularization。
核心定義#
最常見的兩種形態:
- 純資料容器類別——只有資料、沒有操作。
- 方法住在 A 類別,但所有動作對象都在 B 類別。
「資料與操作應該在語意上隸屬的同一個類別中和諧協作。」—— Lanza & Marinescu
違反「區域化相關的資料與方法」即引發此壞味道。
常見成因#
- OO 中的程序式思維:習慣 C 的
struct、Pascal 的record,把資料與函式分離。 - 缺乏對既有設計的認識:大型專案中開發者只看到一小角,不知道方法該擺哪裡。
範例#
範例 1:Device / DeviceData#
設備管理應用中:
DeviceData:只含 public 資料欄位、零方法。Device:持有DeviceData物件,提供存取與操作。
兩者該是同一抽象卻被分割——典型的 Broken Modularization。

Figure 5.4: 設備管理應用中的類別圖(範例 1)
範例 2:Order 類別只擺資料#
電商應用的 Order 只有資料欄位,驗證、稅金、狀態變更等程式碼散落整個應用:

Figure 5.5: 只含 public 資料成員的 Order 類別(範例 2)
後果:
- 改動需動多處。
- 欄位 public → 客戶端可繞過合法的狀態流程,直接從
new跳到closed。
軼事:跨層的 check 功能#
一個多版本設備設定工具:v1.0 的 check 在 UI 層;v1.2 加在 Utility 層;v2.0 連 Business Logic 層也有。沒有任何重構介入。最終 check 散布三層,每次修改都得同步檢視全部。
教訓:小決策也會層層放大。區域化、關注點分離、高內聚低耦合從一開始就要堅持。
建議重構#
套用「convert procedural design to objects」重構:把資料與其行為合到同一類別中。
- 方法在 A 類別中卻更頻繁地操作 B 類別的成員 → move method。
- 欄位在 A 類別中卻被 B 類別大量使用 → move field。

Figure 5.6: 針對 Broken Modularization 壞味道的建議重構
範例 1 的重構#
合併 DeviceData 與 Device 為單一類別。

Figure 5.7: 設備管理應用的建議重構
範例 2 的重構#
Order拆為OrderItem、OrderDetail、Payment。- 將欄位改為 private。
- 將
validateOrder()等方法移回Order。 - 不屬於
Order的成員移到合適的類別。
重構時要注意分寸——把「看似相關」的方法全塞進一個類別,反而會引發 Multifaceted Abstraction(3.4 節)或 Insufficient Modularization(5.2 節)。
對品質屬性的衝擊#
- 理解性:要看懂一個功能必須跨多個類別追蹤資料與方法。
- 可變更性與可擴充性:每次變更都需要動多個類別。
- 可重用性與可測試性:無法以單一抽象重用、測試。
- 可靠性:方法被擺錯地方時,會接觸到不該接觸的內部資料結構或演算法。
別名#
- Class passively stores data:只儲存資料、沒有操作方法。
- Data class:只是「啞」資料容器,但被大量類別倚賴。
- Data records、Record (class):只有欄位、沒有方法(Pascal record 風格)。
- Data container:類別只負責放資料,由另一個類別操作。
- Misplaced operations:應在內部的內聚操作放到了類別外。
- Feature envy:方法對另一個類別的成員「更感興趣」。
- Misplaced control:功能未經正當理由就與資料分離。
實務考量#
自動產生的程式碼#
由模型自動產生的程式碼常含資料類別。直接修改會導致模型與程式碼不同步——接受這類資料類別作為自動產生的副產品較合適。
Data Transfer Objects (DTOs)#
DTO ↗ 用於跨程序傳輸資料、減少遠端呼叫次數。有意聚合資料、不含行為——以利序列化。這不是壞味道,是設計選擇。