??什么是DDD呢?領域驅動設計[DDD]是一種針對復雜需求的軟件開發方法。將軟件實現與不斷發展的模型聯系起來,專注于核心領域邏輯,而不是基礎設施細節。DDD適用于復雜領域和大規模應用,而不是簡單的CRUD應用。它有助于建立一個靈活、模塊化和可維護的代碼庫。
1.《Implementing Domain Driven Design》電子書: https://url39.ctfile.com/f/2501739-610635606-674948?p=2096(訪問密碼:2096)
2.《基于ABP Framework實現領域驅動設計》電子書: https://url39.ctfile.com/f/2501739-610635608-94e753?p=2096(訪問密碼:2096)
3.《Mastering ABP Framework》電子書: https://url39.ctfile.com/f/2501739-610635610-9a8f66?p=2096(訪問密碼:2096)
一.DDD中的領域層和應用層相關概念
DDD主要關注領域層和應用層。
1.DDD中的領域層
領域層中的基本概念有:
(1)實體[Entity]
實體就像面向對象中的對象,它包含屬性和方法,并且有唯一的ID。
(2)值對象[Value Object]
值對象是領域中類型的領域對象。這聽起來很抽象,舉個例子就明白了。比如,訂單Order這個聚合根由一系列的屬性構成:唯一標識ID、OrderDate、OrderItems、Address等。其中Address就是一個值對象。值對象=值+對象=將一個值用對象的方式進行表述,來表達一個具體的固定不變的概念。
(3)聚合[Aggregate]和聚合根[Aggregate Root]?個聚合是一系列對象[實體和值對象]的集合,通過聚合根將所有關聯對象綁定在?起。比如,Issue聚合是由Issue[聚合根]、Comment[實體]和IssuelLabel[值對象]組成的集合。
(4)倉儲[Repository]
倉儲接口定義在領域層,實現在基礎設施層。為什么需要倉儲呢?主要就是解耦數據庫,把增刪查改等數據庫操作和不同類型的數據庫解耦。DDD通用原則之一就是數據庫獨立性原則,領域層和應用層只依賴于倉儲接口,并且倉儲接口不適合使用用任何ORM特殊對象。
(5)領域服務[Domain Service]
領域服務封裝了核心的業務邏輯,它對同一個實體的一個或多個方法進行組合和封裝,或對多個不同實體的操作進行組合或編排,對外暴露成領域服務。
(6)規約[Specification]
規約是?個命名的、可重?的、可組合的和可測試的類,?于根據業務規則過濾領域對象。
(7)領域事件[Domain Event]
通過消息隊列的方式,比如RabbitMQ等,實現一個特定的領域事件發生時,會通知其它的服務。
2.DDD中的應用層
應用層中的基本概念有:
(1)應用服務[Application Service]
通常應用服務層的輸入和輸出都是DTO,并且一個應用服務通常被認為是一個事務。
(2)數據傳輸對象[DTO]
目的主要是解耦應用服務層和展示層。如果沒有DTO,那么應用服務層返回的是完整的對象,包含了展示層并不需要的字段,并且也可能泄露了對象字段信息。
(3)工作單元[Unit Of Work]
簡單理解就是要么全部成功,要么全部失敗。
二.基于ABP模板創建的解決方案結構
基于ABP模板創建的解決方案結構如下所示:1.領域層
(1)IssueTracking.Domain[領域層]:該項?包含實體、值對象、領域服務、規約、倉儲接?等。(2)IssueTracking.Domain.Shared[領域共享層]:通常定義的常量和枚舉,都放在該項?中。
2.應用層
(1)IssueTracking.Application.Contracts[應用契約層]:包含應用服務接口和數據傳輸對象。該項?被應?程序客戶端引用,比如Web項目、API客戶端項目。(2)IssueTracking.Application[應用層]:實現在Contracts項目中定義的接?。
3.展示層
(1)IssueTracking.Web[展示層]:這個是前后端不分離的項目命名方式,那么通常是一個ASP.NET Core MVC/Razor Pages應用。
說明:如果是前后端分離的項目,在解決方案中不會包含該項目,而是通過IssueTracking.HttpApi.Host項目提供HTTP API服務,供客戶端調用。
4.遠程服務層
(1)IssueTracking.HttpApi[遠程服務層]:簡單理解就是很薄的控制層,該項目主要用于定義HTTP API,即應用服務層的包裝器,將它們公開給遠程客戶端調用。
(2)IssueTracking.HttpApi.Client[遠程服務代理層]:當第三方客戶端引用該項目時,就可以直接通過依賴注入使用遠程服務應用,通過基于ABP的動態C#客戶端API代理系統來實現的。
5.基礎層
(1)IssueTracking.EntityFrameworkCore:EF Core核心基礎依賴項目,包含數據上下文、數據庫映射、EF Core倉儲實現等。
(2)IssueTracking.EntityFrameworkCore.DbMigrations:用于管理Code First數據遷移的特殊的工具項目。最新ABP中已經移除了該項目,不用了解了。
6.其它層
(1)IssueTracking.DbMigrator:控制臺應用程序,主要是遷移數據庫結構并初始化種子數據。
三.解決方案中項目依賴關系
該解決方案中項目之間的依賴關系如下:1.Domain.Shared
所有項目直接或間接依賴此項目,此項目中的所有類型都可以被其它項目所引用
2.Domain
僅依賴Domain.Shared項目。
3.Application.Contracts
依賴Domain.Shared項目,可以在DTO中復用Domain.Shared中的類型。
4.Application
依賴Application.Contracts項目,因為此項目需要實現應用服務的接口及接口使用的DTO。另外也依賴Domain項目,因為在應用服務中使用倉儲接口或領域對象。
5.EntityFrameworkCore
依賴Domain項目,因為此項目需要將領域對象[實體或值對象]映射到數據庫的表,另外還需要實現Domain項目中的倉儲接口。
6.HttpApi
依賴Application.Contracts項目,因為Controllers需要注入應用服務接口。
7.HttpApi.Client
依賴Application.Contracts項目,因為此項目需要使用應用服務接口。
8.Web
依賴HttpApi項目,發布定義的HTTP API。另外也間接依賴Application.Contracts項目,可以在頁面/組件中使用應用服務。
看上面解決方案依賴關系圖的虛線部分,就會發現Web項目依賴于Application和EntityFrameworkCore項目。這是因為Web是一個可部署的項目,在應用時需要應用服務和倉儲的實現。這樣框架設計的一個弊端就是在展示層中是可以使用實體和EF Core對象的,但這是嚴格避免的。
四.DDD應用程序執行流程
第1步:無論是瀏覽器中的Web Application,還是遠程客戶端,它們發起HTTP請求到服務器。
第2步:MVC UI或者HTTP API接收并處理請求,在這個階段執行AOP邏輯,比如授權、輸入驗證、異常處理、審計日志、緩存等。MVC Controller在構造函數中注入應用服務接口,調用方法發送和接收DTO對象。
第3步:應用服務使用領域層的對象[實體、倉儲接口、領域服務等]來實現用例,在這個階段同樣執行一些AOP邏輯,比如授權、驗證、審計日志和工作單元等。一個應用服務方法是一個工作單元,具有原子性。
參考文獻:
[1]abp-vnext-pro:https://github.com/WangJunZzz/abp-vnext-pro
[2]iEricLee的ABP博客:https://www.cnblogs.com/YGYH/
[3]cms-kit:https://github.com/abpframework/abp/tree/dev/modules/cms-kit
[4]基于ABP Framework實現領域驅動設計
人工智能干貨推薦專注于人工智能領域的技術分享
游戲元宇宙專注于游戲領域的技術分享