动态

详情 返回 返回

領域驅動設計(Domain-Driven Design) - 动态 详情

DDD

全稱Domain-Driven Design,意為領域驅動設計,是一種軟件開發的方法論,強調通過領域模型來指導複雜系統的設計與開發,核心概念如下

  • 限界上下文(Bounded Context)
  • 實體(Entity)、值對象(Value Object)
  • 聚合(Aggregate)、領域事件(Domain Event)
  • 通用語言(Ubiquitous Language)

DDD & MVC

關注點

  • MVC架構關注於將應用程序的不同部分分為模型(Model/Dao)、視圖(View)和控制器(Controller),以實現分層和關注點分離。它主要解決的問題是用户界面與應用邏輯之間的分離,以及實現交互和數據展示。
  • DDD架構關注於對領域知識的建模和實現,將領域層(Domain Layer)作為核心,並通過領域模型來表達業務領域的概念和規則。它主要解決的問題是在複雜的業務領域中,如何設計和組織代碼以實現業務需求。

層次結構

  • MVC架構分為三個主要層次:模型(Model)、視圖(View)和控制器(Controller)。模型層負責處理數據和業務邏輯,視圖層負責展示數據給用户,控制器層負責處理用户的輸入和操作。
  • DDD架構也分為不同的層次,包括領域層(Domain Layer)、應用層(Application Layer)、基礎設施層(Infrastructure Layer)等。領域層是核心,負責定義和實現領域模型和業務邏輯,應用層負責協調和組織領域層的操作,基礎設施層負責與外部資源的交互。DDD分層依靠事件驅動,通過事件建立模型,合理劃分邊界,建立領域對象,定義符合DDD分層架構思想的代碼模型,以此保證業務模型與代碼模型的一致性。

設計思想不同

  • MVC架構的設計思想是通過分離用户界面、應用邏輯和數據操作,實現可維護、可擴展的應用程序。它強調關注點分離和模塊化設計。
  • DDD架構的設計思想是通過領域模型來表達業務領域的概念和規則,強調將業務邏輯放在核心領域層中,以實現高內聚、鬆耦合的設計。  

DDD基礎

層級劃分

  • 最內層:最基本的數據單位,值對象、屬性集、唯一標識等,不能直接使用。
  • 實體:它將基礎數據進行封裝,在代碼中就是封裝好的一個個實體對象,可直接使用。
  • 領域層:它按照業務劃分為不同的領域,比如訂單領域、商品領域、支付領域等。
  • 應用服務層(業務層):它對業務邏輯進行編排。

通用語言

DDD的核心原則是使用一種基於模型的語言。模型是軟件滿足領域的共同點,它很適合作為這種通用語言的構造基礎。使用模型作為語言的核心骨架,要求團隊在進行所有的交流都是統一的語言,在代碼中也是。

限界上下文

DDD在戰略設計上提出了“限界上下文”這個概念,以避免同樣的概念或語義在不同的上下文環境中產生歧義,用來確定語義所在的領域邊界。在統一的領域邊界內用統一的語言進行交流。

領域交互

領域之間的交互,也可以指不同上下文之間的業務實體要如何實現交互。

DDD中這種機制叫做上下文映射(Context Mapping),一般方法有通過合作關係(一榮俱榮,一損俱損)、防腐層Anti-Corruption(通過一些適配和轉換)、共享內核(依賴部分共享的模型)、依賴關係(有組織的上下游依賴)等。

其中需要特別關注防腐層,是隔離最徹底的做法,強調單獨一層完成上下游的交互,與業務邏輯完全解耦,各自獨立(是優點,也是缺點,存在一定的轉換成本)

ORM(Object-Relational Mapping,對象-關係映射)

多數情況下領域模型和數據模型並不是一一對應的關係,為了彌補二者的差異,要做一層對象關係映射。ORM是一種將對象模型與關係數據庫之間進行映射的技術,主要目標是解決對象關係不匹配的問題,將對象模型和關係數據庫之間的轉換和映射自動化,將數據庫表映射到對象的類和屬性上,從而實現對象和數據庫之間的一致性,ORM框架通常提供了一系列的API和工具,用於執行數據庫操作、查詢、關聯等。

實體與值對象

  • 實體(Entity)
    實體是根據標識,而不是其屬性值來區分的。實體對象在系統中具有持久化的特性,通常會被存儲到數據庫中。擁有唯一標識的對象,它具有可變的狀態和生命週期,實體 = 唯一身份標識 + 可變性【狀態 + 行為】,實體通常被表示為DO(領域對象)的形式。例如,商品(Commodity)可以被認為是一個實體,每個商品都有唯一的商品ID作為標識,並且具有一些可變的屬性,如商品名稱、價格、庫存等。商品可以參與到業務流程中,如下單、支付、發貨等。
  • 值對象(Value Object)
    也稱為數值對象或數據傳輸對象,是用於封裝一組相關屬性的對象,它們沒有唯一的標識,通常用於表示較簡單的概念和屬性組合,是不可變的,它們可以作為實體的屬性或方法的參數,用於傳遞和封裝屬性值。基於其屬性值來判斷值對象是否相等。

充血模型

實體的充血模型強調將業務邏輯和行為封裝在實體中,將實體打造成具有豐富行為和狀態的對象,它不僅僅是簡單的數據容器,還包含了業務邏輯和處理規則。實體負責管理自己的狀態,擁有處理自身行為的方法,以及對外提供操作接口。

聚合與聚合根

  • 聚合
    把一些關聯性極強、生命週期一致的實體、值對象放到一個聚合裏。聚合是領域對象的顯式分組。
    聚合在 DDD 分層架構裏屬於領域層,領域層包含了多個聚合,共同實現核心業務邏輯。跨多個實體的業務邏輯通過領域服務來實現,跨多個聚合的業務邏輯通過應用服務來實現。例如:有的業務場景需要同一個聚合的 A 和 B 兩個實體來共同完成,我們就可以將這段業務邏輯用領域服務來實現;而有的業務邏輯需要聚合 C 和聚合 D 中的兩個服務共同完成,這時你就可以用應用服務來組合這兩個服務。
  • 聚合根
    也稱為根實體,是一種更大範圍的封裝,把一組有相同生命週期,在業務上不可分隔的實體和值對象聚合在一起,通過根實體的唯一標識對外提供能力。它不僅是實體,還是聚合的管理者。
    聚合之間通過聚合根ID關聯引用,如果需要訪問其它聚合的實體,就要先訪問聚合根,再導航到聚合內部實體,外部對象不能直接訪問聚合內實體。   

領域事件

它用來表示在一個特定領域由一個用户動作觸發的,發生在過去的行為產生的事件。領域事件將會導致進一步的業務操作,有助於實現業務的解耦,並完成業務閉環。需要忽略不相關的領域活動,同時明確領域專家要跟蹤或希望被通知的事情,或與其他模型對象中的狀態更改相關聯。

領域事件 = 事件發佈 + 事件存儲 + 事件分發 + 事件處理。

  • 事件發佈:構建一個事件,需要唯一標識,然後發佈;
  • 事件命名:事件是表示發生在過去的事情,在命名上推薦使用Domain Name + 動詞的過去式 + Event,可以更準確地表達業務語義。如:MoneyTransferedEvent表示轉賬成功發出的事件、MoneyTransferFailedEvent表示轉賬失敗發出的事件
  • 事件存儲:發佈事件前需要存儲,因為接收後的事建也會存儲,可用於重試或對賬等;
  • 事件分發:服務內直接發佈給訂閲者,服務外需要藉助消息中間件,比如Kafka,RabbitMQ等;
  • 事件處理:先將事件存儲,然後再處理。 

資源庫(倉儲)

倉儲介於領域模型和數據模型之間,主要用於聚合的持久化和檢索。它隔離了領域模型和數據模型,以便我們關注於領域模型而不需要考慮如何進行持久化。

將暫時不使用的領域對象從內存中持久化存儲到磁盤中。當日後需要再次使用這個領域對象時,根據 key 值到數據庫查找到這條記錄,然後將其恢復成領域對象,應用程序就可以繼續使用它了,這就是領域對象持久化存儲的設計思想。

user avatar king_wenzhinan 头像 xiaoniuhululu 头像
点赞 2 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.