介面層,應用層,核心層,基礎層
Interfaces(介面層): 使用者介面/前端互動/資料展現/處理使用者傳送的Restful請求,解析使用者輸入檔案傳輸給下一層application。資料的組裝、資料傳輸格式以及 Facade 介面等程式碼都會放在這一層目錄裡。
- Assembler: 實現 DTO 與領域物件之間的相互轉換和資料交換。一般來說 Assembler 與 DTO 總是一同出現。
- Dto:它是資料傳輸的載體,內部不存在任何業務邏輯,我們可以透過 DTO 把內部的領域物件與外界隔離。
- Facade:提供較粗粒度的呼叫介面,將使用者請求委派給一個或多個應用服務進行處理。
Application(應用層):應用層服務組合/編排相關程式碼。應用服務向下基於微服務內的領域服務或外部微服務的應用服務完成服務的編排和組合,向上為使用者介面層提供各種應用資料展現支援服務。應用服務和事件等程式碼會放在這一層目錄裡。
Event(事件):這層目錄主要存放事件相關的程式碼。它包括兩個子目錄:publish 和subscribe。前者主要存放事件釋出相關程式碼,後者主要存放事件訂閱相關程式碼(事件處理相關的核心業務邏輯在領域層實現)。
這裡提示一下:雖然應用層和領域層都可以進行事件的釋出和處理,但為了實現事件的統一管理,我建議你將微服務內所有事件的釋出和訂閱的處理都統一放到應用層,事件相關的核心業務邏輯實現放在領域層。透過應用層呼叫領域層服務,來實現完整的事件釋出和訂閱處理流程。Service(應用服務):這層的服務是應用服務。應用服務會對多個領域服務或外部應用服務進行封裝、編排和組合,對外提供粗粒度的服務。應用服務主要實現服務組合和編排,是一段獨立的業務邏輯。你可以將所有應用服務放在一個應用服務類裡,也可以把一個應用服務設計為一個應用服務類,以防應用服務類程式碼量過大。
Domain(領域層):它主要存放領域層核心業務邏輯相關的程式碼。領域層可以包含多個聚合程式碼包,它們共同實現領域模型的核心業務邏輯。聚合以及聚合內的實體、方法、領域服務和事件等程式碼會放在這一層目錄裡。Domain 是由一個或多個聚合包構成,共同實現領域模型的核心業務邏輯。聚合內的程式碼模型是標準和統一的,包括:entity、event、repository 和 service 四個子目錄。
Aggregate(聚合):它是聚合軟體包的根目錄,可以根據實際專案的聚合名稱命名,比如許可權聚合。在聚合內定義聚合根、實體和值物件以及領域服務之間的關係和邊界。聚合內實現高內聚的業務邏輯,它的程式碼可以獨立拆分為微服務。以聚合為單位的程式碼放在一個包裡的主要目的是為了業務內聚,而更大的目的是為了以後微服務之間聚合的重組。聚合之間清晰的程式碼邊界,可以讓你輕鬆地實現以聚合為單位的微服務重組,在微服務架構演進中有著很重要的作用。
- Entity(實體):它存放聚合根、實體、值物件以及工廠模式(Factory)相關程式碼。實體類採用
充血模型
,同一實體相關的業務邏輯都在實體類程式碼中實現。跨實體的業務邏輯程式碼在領域服務中實現。 - Event(事件):它存放事件實體以及與事件活動相關的業務邏輯程式碼。
- Service(領域服務):它存放領域服務程式碼。一個領域服務是多個實體組合出來的一段業務邏輯。你可以將聚合內所有領域服務都放在一個領域服務類中,你也可以把每一個領域服務設計為一個類。如果領域服務內的業務邏輯相對複雜,我建議你將一個領域服務設計為一個領域服務類,避免由於所有領域服務程式碼都放在一個領域服務類中,而出現程式碼臃腫的問題。領域服務封裝多個實體或方法後向上層提供應用服務呼叫。
- Repository(倉儲):它存放所在聚合的查詢或持久化領域物件的程式碼,通常包括倉儲介面和倉儲實現方法。為了方便聚合的拆分和組合,我們設定了一個原則:一個聚合對應一個倉儲。特別說明:按照 DDD 分層架構,倉儲實現本應該屬於基礎層程式碼,但為了在微服務架構演進時,保證程式碼拆分和重組的便利性,我是把聚合倉儲實現的程式碼放到了聚合包內。這樣,如果需求或者設計發生變化導致聚合需要拆分或重組時,我們就可以將包括核心業務邏輯和倉儲程式碼的聚合包整體遷移,輕鬆實現微服務架構演進。
- Entity(實體):它存放聚合根、實體、值物件以及工廠模式(Factory)相關程式碼。實體類採用
Infrastructure(基礎層):它主要存放基礎資源服務相關的程式碼,為其它各層提供的通用技術能力、三方軟體包、資料庫服務、配置和基礎資源服務的程式碼都會放在這一層目錄裡。
- Config:主要存放配置相關程式碼。
- Util:主要存放平臺、開發框架、訊息、資料庫、快取、檔案、匯流排、閘道器、第三方類庫、通用演算法等基礎程式碼,你可以為不同的資源類別建立不同的子目錄。
- interfaces
- assembler
- dto
- facade
- application
- event
- publish
- subscribe
- service
- domain
- aggregate0 ...
- entity
- event
- repository
- service
- infrastructure
- config
- util ...
- api
- driver
- eventbus
- mq
那關於程式碼模型我還需要強調兩點內容。
第一點:聚合之間的程式碼邊界一定要清晰。聚合之間的服務呼叫和資料關聯應該是儘可能的松耦合和低關聯,聚合之間的服務呼叫應該透過上層的應用層組合實現呼叫,原則上不允許聚合之間直接呼叫領域服務。這種松耦合的程式碼關聯,在以後業務發展和需求變更時,可以很方便地實現業務功能和聚合程式碼的重組,在微服務架構演進中將會起到非常重要的作用。
第二點:你一定要有程式碼分層的概念。寫程式碼時一定要搞清楚程式碼的職責,將它放在職責對應的程式碼目錄內。應用層程式碼主要完成服務組合和編排,以及聚合之間的協作,它是很薄的一層,不應該有核心領域邏輯程式碼。領域層是業務的核心,領域模型的核心邏輯程式碼一定要在領域層實現。如果將核心領域邏輯程式碼放到應用層,你的基於 DDD 分層架構模型的微服務慢慢就會演變成傳統的三層架構模型
了。
本作品採用《CC 協議》,轉載必須註明作者和本文連結