基于事件驱动架构构建微服务第2部分:领域对象和业务规则
原文鏈接:https://logcorner.com/building-microservices-through-event-driven-architecture-part2-domain-objects-and-business-rules/
在本文中,我將實現領域模型:
EduSync.Speech.Domain
這是包含核心域的最內層。它包含我們的領域對象和業務規則。并定義我們的外部接口。
不允許使用數據庫、網絡連接、文件系統、UI或特殊框架。
核心領域對自身以外的任何事物一無所知。
這些依賴項及其實現使用接口注入到我們的核心域中。
在上一步結束時,我們最終得到了一個貧血領域模型。所以讓我們從豐富它開始。
充血領域模型
貧血領域模型是DDD世界中的一種反模式,因此在本節中,我將使用值對象將領域模型與數據契約分離。
貧血領域模型是一種領域模型,其中數據和對該數據的操作彼此分離。換句話說,只有屬性的類和處理這些屬性的方法位于另一個類中。
因此,這些其他類既可以讀取數據,也可以修改數據。所以領域類必須有public setter。這是缺乏封裝反模式。
讓我們從驗證Title開始。
我的第一個測試是:Title長度必須大于10個字符且小于60個字符:
測試將失敗,因此讓我們實現Title驗證:
Title值對象
實體和值對象的主要區別在于如何識別它們。
實體由引用相等和標識相等標識。
值對象由引用相等和結構相等來標識。
引用相等:如果兩個對象引用內存中的同一個對象,則它們相等
標識相等:如果兩個對象具有相同的標識,則它們相等
結構相等:如果兩個對象的所有成員都相等,則兩個對象相等
實體具有Id字段并且是可變的,而值對象沒有Id字段并且是不可變的。
值對象沒有實體就沒有意義,它必須屬于一個實體。
考慮以下情況:
2輛相同型號、相同顏色、相同年齡等的車輛……總是2輛不同的車輛,因為每輛車都有自己的標識:車輛是一個實體。
2個所有字段都相等的地址(相同的街道號碼、相同的城市、相同的國家,等等)是完全相同的地址:地址是一個值對象。
Title的第一個實現如下所示:
請記住,值對象由引用相等和結構相等來標識.
所以右鍵單擊Title類并選擇生成 Equals和GetHashCode。
Title只有一個值,因此選擇它并單擊確定
Title現在是一個值對象,它的最終實現看起來像這樣
這是Title值對象的單元測試。如果它們具有相同的值,我應該驗證2個標題是否相等,如果不是,則不同
URL值對象
驗證Url的所有邏輯都在名稱為UrlValue的值對象中實現
Type值對象
驗證SpeechType的所有邏輯都在名稱為SpeechType的值對象中實現
Speech領域對象如下所示:
實體和聚合
請記住,實體由引用相等和標識相等標識并具有Id字段。因此,讓我們創建一個基本實體類:Entity,并在Id字段上生成Equals和GetHashCode。如果2個實體E1和E2具有相同的id,則 E1==E2應該返回true
DDD聚合是可以作為單個單元處理的領域對象的集群。例如訂單及其訂單項,它們將是單獨的對象,但將訂單(及其訂單項)視為單個聚合非常有用。
聚合應該始終處于有效狀態,并且每個聚合都有一個根是一個實體,不屬于該聚合的類只能引用聚合根。
因此,讓我們創建一個繼承自Entity的基類AggregateRoot,我將其設為泛型,因為T是Id字段的類型,并且它可以根據這些實體而變化?
領域事件
領域事件通過避免直接調用來實現有界上下文之間的通信。所以一個有界上下文B1引發一個事件,一個或多個有界上下文B2…Bn對此事件的子訂閱方應該處理該事件以使用它。
因此,讓我們創建一個基類DomainEvent?
但是在這里,由于我實施事件溯源的策略,我的有界上下文產生的所有事件都將保存在我的事件存儲中。對這些事件感興趣的其他有界上下文、服務或其他程序將必須訂閱服務總線。
比如我每次創建一個新的Speech,然后我都會創建一個SpeechCreatedEvent事件
SpeechCreatedEvent類必須從DomainEvent基類繼承?
聚合根的最終實現將如下所示:?
因為Speech實體是聚合根,所以讓我們繼續從AggregateRoot繼承它,Speech實體的Id字段是一個 Guid
讓我們添加一些測試來覆蓋 domainEvents?
LogCorner.EduSync.Speech.Application和LogCorner.EduSync.Speech.Domain是100%的代碼覆蓋率?
歡迎關注我的個人公眾號”My IO“
總結
以上是生活随笔為你收集整理的基于事件驱动架构构建微服务第2部分:领域对象和业务规则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Blazor 组件之间使用 EventC
- 下一篇: 谈谈为什么我们需要云原生架构?