領域驅動設計(Domain-Driven Design, DDD)是一種軟體設計哲學,旨在透過深入理解業務領域的複雜性來指導軟體專案的設計和開發,以確保軟體能夠準確地解決業務問題。DDD提倡透過深入業務領域的知識合作,以及業務領域專家的緊密合作,來尋找和實現軟體解決方案。這種方法論主要關注的是業務邏輯的複雜性管理,而不是技術實現的複雜性。
參考文件:
1、領域(Domain)
領域是指特定業務領域的知識、業務活動和業務過程。它是DDD中最基本的概念,所有的設計和開發工作都是為了更好地理解和實現業務領域的需求。在DDD中,領域是指我們軟體所要解決問題的業務範圍,它是軟體開發的目標和基礎。領域包含了特定業務領域內的邏輯、資料、操作以及業務規則。領域的定義應該是清晰和具體的,以確保開發團隊能夠準確理解業務需求和業務背景。
深入理解領域是開發高質量軟體的前提,這種理解確保軟體能夠有效地解決實際問題。為了促進團隊成員間的有效溝通,定義領域概念和術語至關重要,它允許開發者和非技術人員使用一種共同的語言,從而減少誤解和溝通成本。此外,領域的清晰界定對指導軟體的設計和架構極為重要,確保軟體結構能夠緊密貼合業務邏輯,使之易於理解和維護。
2、限界上下文(Bounded Context)
限界上下文是DDD中的一個核心概念,它定義了特定領域模型的邊界。這個概念幫助團隊理解和劃分複雜系統中的不同部分,使得每個部分都有一個明確的職責、業務規則和術語,這樣可以避免不同領域模型之間的混淆和衝突。
限界上下文在領域驅動設計中發揮著核心作用,主要體現在三個方面:首先,它透過清晰界定邊界來明確哪些概念、業務規則和資料屬於特定的領域模型,有效減少不同模型間的耦合。其次,限界上下文內部的團隊成員採用統一的語言(Ubiquitous Language)進行溝通,保證對業務術語的共同理解,以避免溝通障礙。最後,限界上下文的劃分促進了系統的模組化,使得大型複雜系統能夠被分割成更小、更易於管理和維護的部分,從而提升了整體的開發效率和系統的可維護性。
限界上下文在領域驅動設計中扮演著至關重要的角色,它不僅幫助開發團隊清晰地理解和劃分系統的不同部分,還促進了團隊成員間有效的溝通。正確地識別和定義限界上下文是實現領域驅動設計成功的關鍵步驟。
3、領域模型(Domain Model)
領域模型是對特定領域內知識和業務活動的抽象表示,通常透過類圖或其他建模技術來表達。它是理解領域和指導設計及開發的基礎。領域模型,作為領域驅動設計(DDD)中的一個核心概念模型,旨在精確表示和深入理解特定業務領域內的相關概念、業務規則以及業務活動。這種模型的構建依託於實體(Entities)、值物件(Value Objects)、聚合(Aggregates)、領域事件(Domain Events)和服務(Services)等基本構件,透過這些元素綜合表達業務邏輯和組織結構。領域模型的主要目的在於提供一個內容豐富且語義明確的業務領域的表示形式,這樣做不僅促進了開發團隊與業務專家之間的有效溝通,還確保了軟體設計和實現過程能夠更加準確地反映業務需求。
領域模型的設計突出了幾個關鍵特點:其一,豐富性,能夠全面表達業務領域的複雜性,涵蓋了業務實體的各種屬性和行為,以及這些實體間的相互關係;其二,語言一致性,透過建立統一的領域語言(Ubiquitous Language),它幫助團隊成員之間消除溝通障礙,保證了技術解決方案與業務需求之間的一致性;其三,靈活性,領域模型在設計時充分考慮到了業務需求的變化和演進,從而確保模型能夠輕鬆適應於業務規則的變動。綜合這些特點,領域模型不僅加深了對業務領域的理解,也極大地促進了軟體專案的成功實施。
4、實體(Entity)
實體是具有唯一識別符號的領域物件,即使其他屬性發生變化,其身份也保持不變。實體通常用於表示業務領域中的關鍵概念和業務實體。在領域驅動設計中,實體是透過唯一識別符號(ID)定義的,這個ID是實體最關鍵的特徵,確保了即使實體的其他屬性發生變化,只要這個標識保持不變,它就仍然被視為同一實體。這種設計不僅反映了現實世界中事物的連續性和一致性,即使它們的某些特性可能隨時間變化,但其身份的不變性保持其獨特性。實體還擁有一個定義明確的生命週期,包括建立、更新和刪除等過程,在整個應用程式的生命週期內,這些實體會持續存在並隨時間發展。這種生命週期管理反映了實體如何適應和響應業務邏輯和操作中的變化,確保了系統的靈活性和響應性。
實體在領域驅動設計中起著核心作用,它們不僅封裝了資料,還包括與該實體相關的業務規則和行為,使得操作實體的邏輯既內聚又易於管理和維護。作為領域模型的關鍵組成部分,實體使得模型能夠更精確地對映現實世界的業務邏輯和規則。此外,實體的狀態需要被持久化到資料庫中,而實體的唯一標識使得檢索、更新和刪除資料變得簡單高效,從而最佳化了資料管理過程。這三個方面共同強調了實體在捕捉、維護和表達業務領域複雜性中的重要性。
實體與DDD中的另一個核心概念“值物件”(Value Object)相對。二者的主要區別在於,值物件沒有唯一標識,它們透過其屬性的值來定義。值物件通常是不可變的,而實體則可以改變。在設計領域模型時,識別哪些概念是實體,哪些是值物件,對於構建一個清晰、高效的模型至關重要。
實體在領域驅動設計中扮演著重要角色,它們幫助開發者在軟體設計中更好地理解和建模業務領域。透過合理使用實體,可以提高軟體的可維護性和可擴充套件性,更好地應對業務需求的變化。
5、值物件(Value Object)
值物件是不需要唯一識別符號的領域物件,它描述了領域中的某種屬性或者概念,其身份完全由它的屬性值確定。值物件的核心特性包括不可變性、相等性、無身份和側重行為。一旦建立,值物件的屬性不應更改;任何狀態變化都需透過建立新例項來實現,確保了其不可變性。它們的相等性基於屬性值而非身份,如記憶體地址或ID,意味著若兩個值物件的所有屬性值相同,則視為相等。不同於擁有唯一識別符號的實體(Entity),值物件透過其屬性值定義,無需身份。此外,值物件可以含有方法,這些方法專注於執行與物件相關的邏輯操作,而非狀態改變,從而強調了其行為側重的特點。
值物件在領域驅動設計中扮演著至關重要的角色,它們透過幾個關鍵方面顯著提升了軟體設計的質量和效率。首先,值物件非常適合於描述那些在其生命週期內不變的屬性,如貨幣和時間段,這樣的設計不僅使得模型更加真實,還確保了資料的一致性。其次,透過將相關的值和行為封裝在一起,值物件能夠簡化領域邏輯,使得整個領域模型更加清晰、易於理解和維護。此外,值物件的不可變性天生支援執行緒安全,這一點在處理併發環境時尤為重要,能夠有效提高系統的效能和穩定性。最後,值物件透過限制狀態的變更和強化物件的不變性,幫助開發者減少了軟體開發中的錯誤,進一步提升了軟體質量。總之,值物件透過這些機制,為構建高質量、高效能和可維護的軟體系統提供了堅實的基礎。
6、聚合(Aggregate)
聚合是一組具有內聚關係的物件集合,這些物件被視為一個單一的單元進行處理。在DDD中,聚合用來封裝業務規則,確保資料的一致性和完整性。每個聚合都有一個根實體(Aggregate Root),它是聚合內部其他物件的入口點。聚合根持有聚合內部物件的引用,並確保聚合的規則和約束被維護。
聚合作為領域驅動設計中的一個核心概念,透過封裝業務規則和資料來確保業務操作的一致性,其中任何修改都是透過聚合根進行,以維護資料的完整性。每個聚合都定義了清晰的邊界,聚合內部的物件對外部隱藏,這降低了系統的複雜性,使開發者只需關注聚合的介面而不是其內部實現。聚合之間保持獨立性,允許單獨對聚合進行修改和維護,而不會影響到其他聚合。此外,聚合還定義了一致性和事務的邊界,在聚合內部可以保證強一致性,而聚合之間的一致性可能是最終一致性,這樣的設計既保障了資料的準確性,也提高了系統的靈活性和可維護性。
聚合的設計遵循幾個關鍵原則以確保其效用和一致性。首先,選擇合適的聚合根至關重要,它應當能夠代表整個聚合並作為外界與聚合互動的唯一入口。其次,聚合應保持儘可能小的規模以簡化管理,同時確保能夠維護業務規則和資料一致性。此外,為了保持聚合的獨立性和減少直接依賴,聚合之間的關聯應透過識別符號實現,而非直接引用。最後,確定一致性邊界是關鍵,需要明確哪些業務操作必須在同一個事務內完成以確保資料的一致性。這些原則共同作用,確保聚合既能有效封裝業務邏輯,又能維護系統的健壯性和靈活性。
聚合在處理複雜業務邏輯、維護資料一致性和封裝業務規則時非常有用。它們在電子商務、金融系統、訂單管理等領域尤其常見,這些領域中的業務規則通常比較複雜,需要精心設計的模型來維護資料的一致性和完整性。
7、聚合根(Aggregate Root)
聚合根是聚合中的一個實體,它充當聚合的入口點。外部物件只能透過聚合根與聚合內的其他物件互動,這有助於維護聚合的邊界和一致性。聚合根的主要作用是維護聚合的完整性和一致性。它負責執行所有對聚合內部物件的操作和訪問控制,確保聚合內的業務規則和不變數得到遵守。透過這種方式,聚合根幫助隔離領域模型的複雜性,並確保領域邏輯的封裝性。
透過使用聚合根,領域驅動設計幫助開發者建立出更加模組化、可維護和業務邏輯清晰的軟體系統。聚合根的概念強調了在設計系統時,圍繞業務領域的核心概念進行思考的重要性,這有助於保證軟體解決方案的業務相關性和技術的準確性。
8、領域服務(Domain Service)
領域服務是一種在領域模型中實現領域邏輯的方式,它代表了一些操作或業務邏輯,這些邏輯不屬於實體或值物件。領域服務通常是無狀態的,並操作領域內的多個實體或值物件。
領域服務是領域驅動設計中的關鍵組成部分,其核心在於提供一種無狀態的解決方案,不直接儲存任何業務狀態資訊,而是專注於執行跨越多個模型或實體的特定業務邏輯,尤其是那些不屬於單個實體上的操作。這種服務通常會與多個領域實體或值物件進行互動,完成其業務任務。應用領域服務的場景包括跨實體操作、複雜邏輯處理和領域規則的封裝。當操作需要跨越多個實體或值物件而不自然屬於任何單一實體或值物件時,領域服務便承擔起責任;同樣,對於那些會讓實體或值物件變得過於複雜、影響其清晰性和單一職責的操作,也由領域服務來處理。此外,領域服務能夠封裝一系列複雜的業務規則或邏輯判斷,透過這種方式,能夠保持模型的簡潔和易於理解,同時確保業務邏輯的集中性和一致性。
領域服務是領域驅動設計中的一個重要概念,它幫助開發者將業務邏輯組織在合適的地方,既不會讓實體和值物件過於臃腫,也保證了業務邏輯的集中性和一致性。正確地識別和實現領域服務對於構建一個健壯、靈活且易於維護的系統至關重要。
9、 應用服務(Application Service)
應用服務定義了軟體對外提供的介面或服務,它使用領域模型和領域服務來實現特定的業務用例。應用服務處理應用層邏輯,如事務管理和安全性,同時協調領域層的物件來執行業務邏輯。應用服務的主要職責是協調領域物件(實體和值物件)來執行具體的業務操作。它是領域邏輯的直接消費者,並透過委託給領域服務或直接使用領域模型來完成業務邏輯。
應用服務在領域驅動設計中扮演著至關重要的角色,它透過協調領域物件和領域服務來完成業務用例,確保業務規則和邏輯的正確執行。它不僅負責管理業務操作的事務以保證操作的一致性和完整性,還為外部客戶端提供介面(如REST API),以隱藏領域模型的複雜性並提供簡潔的操作介面。此外,應用服務還能進行許可權校驗,確保只有具備足夠許可權的使用者能夠執行特定操作,並負責處理和校驗外部輸入及準備輸出資料。
在設計應用服務時,有幾個關鍵的設計準則需要遵循。首先,儘管應用服務負責協調業務流程,但應避免包含業務規則或邏輯,這些應當封裝在領域模型內。其次,應用服務應為特定的業務用例提供細粒度的介面,而非設計一個包羅永珍的通用介面。最後,應用服務應明確界定其職責範圍,不包含使用者介面邏輯或資料持久化邏輯,這些分別由UI層和倉儲層處理。遵循這些設計準則,可以確保應用服務的清晰界限和高效運作,從而使整個系統更加靈活和可維護。
10、倉儲(Repository)
倉儲為領域模型中的聚合提供了持久化機制,它抽象了底層資料庫的細節,提供了查詢和儲存聚合根的方法。在DDD中,"倉儲"(Repository)是一個核心概念之一,主要用於抽象化領域模型和資料儲存之間的互動。
倉儲是一個設計模式,用於封裝儲存、檢索和搜尋領域物件的邏輯,使得應用層不需要直接與資料對映層互動。它為領域模型提供了一個集合式的介面,用於訪問領域物件,而不是透過傳統的資料庫訪問技術。其目的是使得領域設計與資料儲存技術解耦,提高程式碼的可維護性和可測試性。
倉儲在領域驅動設計中扮演著關鍵角色,為領域模型中的聚合根提供了一個集合式的介面,涵蓋新增、刪除、更新和查詢等操作,實現了對領域物件全面的管理。它封裝了所有與資料來源互動的查詢邏輯,允許應用層透明地執行復雜查詢,無需直接處理SQL語句或其他查詢語言,簡化了資料訪問過程。此外,倉儲還負責領域物件的持久化,確保記憶體中的物件狀態能夠被儲存到資料庫或其他持久儲存中。透過這種方式,倉儲模式有效地隔離了領域和資料對映層,使應用層程式碼能夠完全獨立於底層資料儲存細節,從而便於適應儲存技術的變化,增強了系統的靈活性和可維護性。
在實現倉儲時,通常會針對每個聚合根設計一個倉儲介面,定義該聚合根所需的所有持久化操作。這個介面然後可以有多種實現方式,比如使用關係型資料庫、NoSQL資料庫或者記憶體資料庫等。
透過正確實現和使用倉儲模式,可以大大提升領域驅動設計專案的質量和維護性。這要求開發者深入理解領域模型,以及如何在倉儲實現中有效地管理和訪問這些模型。
11、工廠(Factory)
工廠用於建立複雜的物件,尤其是聚合根和聚合。工廠隱藏了建立物件的細節,確保物件在建立時就處於有效狀態。在DDD中,工廠(Factory)是一個核心概念,用於建立複雜的領域物件,同時隱藏建立邏輯的複雜性。
工廠在領域驅動設計中扮演著核心角色,透過封裝物件的建立邏輯,它不僅將物件的建立過程與使用過程分離,從而降低系統的耦合度,而且還確保客戶端無需深入瞭解物件是如何被建立和組裝的,只需透過工廠即可獲得物件例項。此外,工廠方法在建立物件時能夠保證物件例項自建立之初就滿足所有業務規則和約束條件,確保了物件狀態的一致性和有效性。在處理複雜物件的建立時,工廠方法特別有用,它能隱藏物件構建的複雜性,即使構建過程需要多個步驟或依賴多個其他物件,工廠也能透過提供一個簡單的介面簡化這一過程。最重要的是,工廠模式支援多型性,允許在執行時根據不同條件返回不同類的物件,這些物件遵循相同的介面或繼承同一個父類,極大地增加了程式碼的靈活性和可擴充套件性。透過使用工廠模式,可以使領域模型更加清晰和健壯,同時提高了程式碼的可維護性和可擴充套件性。
參考文件: