組織 Domain Logic 是企業應用架構中最核心的決策之一。Fowler 將 Domain Logic 的組織方式分為三種主要模式:Transaction Script、Domain Model 和 Table Module。
三種主要模式#
Transaction Script#
Transaction Script 是最直觀的做法——為每個使用者操作(或商業交易)撰寫一個程序。
本質上,它是一個接收 Presentation 層輸入的程序,經過驗證和計算後,將資料存入資料庫,再將結果回傳給 Presentation 層。每個操作對應一個程序,程序可以被拆分為子程序供不同 Transaction Script 共用。
優點:
- 簡單的程序式模型,大多數開發者都能理解
- 與簡單的 Data Source 層(Row Data Gateway 或 Table Data Gateway)配合良好
- 交易邊界容易設定——開始一個交易,結束時關閉
缺點:
- 隨著 Domain Logic 複雜度增加,重複程式碼越來越多
- 即使抽取共用子程序,重複仍然難以發現和消除
- 最終會變成一團沒有清晰結構的混亂程序

Figure 2.1: A Transaction Script's way of calculating revenue recognitions
Domain Model#
Domain Model 是物件導向的方式——圍繞領域中的名詞(如租約、資產、出貨等)建構物件模型。每個物件包含相關的邏輯,而非將所有邏輯放在一個程序中。
優點:
- 一旦習慣後,可以優雅地處理越來越複雜的邏輯
- 透過新增策略物件等 OO 技術來擴展功能
- 許多開發者一旦使用 Domain Model 就「終身受用」
缺點:
- 學習曲線陡峭——開發團隊可能需要數月才能適應範式轉換
- Domain Model 越豐富,與關聯式資料庫的映射就越複雜(通常需要 Data Mapper)
- 對不熟悉 OO 的開發者來說,找到行為散佈在哪些物件中是一大挑戰

Figure 2.2: A Domain Model's way of calculating revenue recognitions
Table Module#
Table Module 是 Transaction Script 和 Domain Model 之間的折衷方案。它為資料庫中的每個 table 建立一個類別(而非每筆 row),以 Record Set 作為資料載體。
優點:
- 比 Transaction Script 更有結構,減少重複
- 與 Record Set 基礎的 GUI 環境完美搭配(如 .NET 與 Visual Studio)
- 在有 Record Set 工具支援的平台上非常有吸引力
缺點:
- 無法使用 Domain Model 中的細緻 OO 技術(如繼承、策略模式)
- 在沒有 Record Set 支援的環境中,不值得使用

Figure 2.3: Calculating revenue recognitions with a Table Module
如何選擇#
選擇哪種模式取決於 Domain Logic 的複雜度。隨著複雜度增加,Transaction Script 和 Table Module 的維護成本會指數性上升,而 Domain Model 的維護成本則相對線性。
影響選擇的因素:
- 團隊熟悉度:熟悉 Domain Model 的團隊會降低其初始成本
- 平台工具支援:有 Record Set 工具的環境讓 Table Module 更有吸引力
- 這三種模式並非互斥——可以同時用 Transaction Script 處理部分邏輯,Domain Model 處理其餘部分

Figure 2.4: Relationships between complexity and effort for different domain logic styles
如果選錯了方向:從 Transaction Script 重構到 Domain Model 是值得的;但從 Domain Model 回退到 Transaction Script 通常意義不大(除非你能因此簡化 Data Source 層)。
Service Layer#
Service Layer 是一種常見的做法——在底層的 Domain Model 或 Table Module 之上放置一層服務。
Service Layer 的角色#
- 提供一組清晰的 API,作為應用程式的對外介面
- 適合放置交易控制和安全性邏輯
- Presentation 層透過 Service Layer 與 Domain 互動
該放多少邏輯在 Service Layer#
Service Layer 的「厚薄」是一個關鍵決策:
- 最薄的 Service Layer:純粹的 Facade,所有業務邏輯在底層物件中
- 最厚的 Service Layer:大部分邏輯以 Transaction Script 形式放在 Service Layer 中,底層物件很簡單
- 中間路線(Controller-Entity 風格):每個 use case 的特定邏輯放在 Service Layer,通用邏輯放在 Domain 物件中
作者偏好最薄的 Service Layer——只在需要時才加入,而且傾向讓它只做 Facade。不過,許多優秀的設計者會在 Service Layer 中放入較多邏輯,這也是可行的做法。