貧血模型與充血模型比較 - DDD - The Domain Driven Design
在這篇文章中使用Vaughn Vernon的書[ IDDD,2013 ] 的例子來描述SCRUM模型的情景,並能夠以實際的方式展示貧血模型和富模型的實現之間的區別。
讓我們說產品負責人:
允許將每個積壓項分配給Sprint。如果它已經分配給不同的Sprint,則必須先將其解除分配。分配完成後,通知相關方。
一個非常簡單的場景,可以在下面分層顯示:
儘管在圖中有表示,但我們將在示例中忽略Task。
貧血模型
領域/實體
public class Sprint { public int Id { get; set; } public IList<BacklogItem> BacklogItems { get; set; } public SprintStatusEnum Status { get; set; } public string Description { get; set; } public DateTime BeginDate { get; set; } public DateTime EndDate { get; set; } } public class BacklogItem { public int Id { get; set; } public IList<Task> Tasks { get; set; } public int? SprintId { get; set; } public int? UserId { get; set; } public BacklogItemStatusEnum Status { get; set; } public string Description { get; set; } public DateTime? BeginDate { get; set; } public DateTime? EndDate { get; set; } } |
領域/服務
public class SprintServices : ISprintServices { private readonly ISprintRepository _sprintRepository; private readonly IBacklogItemRepository _backlogItemRepository; public SprintServices(ISprintRepository sprintRepository, IBacklogItemRepository backlogItemRepository) { _sprintRepository = sprintRepository; _backlogItemRepository = backlogItemRepository; } public void InsertBacklogItem(int sprintId, int backLogItemId) { var sprint = _sprintRepository.GetById(sprintId); var backLogItem = _backlogItemRepository.GetById(backLogItemId); backLogItem.SprintId = sprintId; backLogItem.Status = BacklogItemStatusEnum.Committed; EmailService.SendMail("destination@email.com", $"The backlog item '{backLogItem.Description}' was assigned to Sprint '{sprint.Description}'"); _backlogItemRepository.Update(backLogItem); } } |
請注意,它們的實體沒有業務邏輯,每個規則都依賴領域服務,實體屬性設定沒有任何控制,設定這些屬性後沒有驗證,聚合不生成域事件。
這樣的物件只是資料容器。
現在看看富血模型......
域/實體
public class Sprint : Entity { public Sprint(string description, DateTime beginDate, DateTime endDate) { Status = SprintStatusEnum.New; Description = description; BeginDate = beginDate; EndDate = endDate; Validate(); } public int Id { get; private set; } public IList<BacklogItem> BacklogItems { get; private set; } public SprintStatusEnum Status { get; private set; } public string Description { get; private set; } public DateTime BeginDate { get; private set; } public DateTime EndDate { get; private set; } public void SetStatus(SprintStatusEnum status) => Status = status; public void SetDescription(string description) => Description = description; public void SetBeginDate(DateTime beginDate) => BeginDate = beginDate; public void SetEndDate(DateTime endDate) => BeginDate = endDate; public void Validate() { if (string.IsNullOrEmpty(Description)) { throw new Exception("Description can not be null"); } if (BeginDate > EndDate) { throw new Exception("EndDate must be greater than BeginDate"); } //more rules... } } public class BacklogItem : Entity { public BacklogItem(string description) { Status = BacklogItemStatusEnum.New; Description = description; Validate(); } public int Id { get; private set; } public IList<Task> Tasks { get; private set; } public int? SprintId { get; private set; } public int? UserId { get; private set; } public BacklogItemStatusEnum Status { get; private set; } public string Description { get; private set; } public DateTime? BeginDate { get; private set; } public DateTime? EndDate { get; private set; } public void SetSprintId(int? sprintId) => SprintId = sprintId; public void SetUserId(int? userId) => UserId = userId; public void SetStatusToNew() => Status = BacklogItemStatusEnum.New; public void SetStatusToCommitted() => Status = BacklogItemStatusEnum.Committed; public void SetStatusToApproved() => Status = BacklogItemStatusEnum.Approved; public void SetStatusToDone() => Status = BacklogItemStatusEnum.Done; public void SetDescription(string description) => Description = description; public void SetBeginDate(DateTime? beginDate) => BeginDate = beginDate; public void SetEndDate(DateTime? endDate) => BeginDate = endDate; public void CommitToSprint(Sprint sprint) { if (IsCommittedToSprint()) { UncommitFromSprint(); } SetStatusToCommitted(); SetSprintId(sprint.Id); this.AddDomainEvent(new BacklogItemCommitted { Id = Id, SprintId = SprintId.Value }); } public void UncommitFromSprint() { SprintId = null; this.AddDomainEvent(new BacklogItemUncommitFromSprint { Id = Id, SprintId = SprintId.Value }); } public bool IsCommittedToSprint() => SprintId != null && SprintId != default(int); public void Validate() { if (string.IsNullOrEmpty(Description)) { throw new Exception("Description can not be null"); } //more rules... } } |
應用:
public class BoardApplication : IBoardApplication { private readonly ISprintRepository _sprintRepository; private readonly IBacklogItemRepository _backlogItemRepository; public BoardApplication(ISprintRepository sprintRepository, IBacklogItemRepository backlogItemRepository) { _sprintRepository = sprintRepository; _backlogItemRepository = backlogItemRepository; } public void ToAllocateBacklogItemToaSprint(int sprintId, int backLogItemId) { var sprint = _sprintRepository.GetById(sprintId); var backLogItem = _backlogItemRepository.GetById(backLogItemId); backLogItem.CommitToSprint(sprint); _backlogItemRepository.Update(backLogItem); } } |
你能看到區別麼?
第一個例子使用了一種非常以資料為中心的方法,而不是行為方法。它不是一個真正的領域模型。
在我們的Rich Model示例中,我們使用表達泛在語言的域物件的行為。
它不會向客戶端公開資料屬性,而是公開一種行為,該行為明確且清楚地表明客戶可以將Backlog專案分配給Sprint。
如果不將此豐富的行為插入Backlog項,則客戶端必須處理事件,這是非常錯誤的。
在第二個例子中,好處要大得多。
現在,您能看到使用Rich Model的好處嗎?
相關文章
- 貧血模型 - DDD - The Domain Driven Design模型AI
- 從貧血模型到充血模型模型
- 談DDD與貧血領域模型:再次為失血模型辯護 -Codecentric AG部落格模型
- 聊一聊領域驅動與貧血模型模型
- OSI模型 與 DOD模型的比較模型
- 英文DDD培訓線上課程推薦: 從失血模型重構到充血模型模型
- 併發模型比較模型
- DDD中事件與命令比較事件
- DDD中簡單模型比複雜模型更危險模型
- 規則引擎與ML模型的比較 - xLaszlo模型
- 元學習:人類與大模型比較建模大模型
- Domain-Driven+Design+Tackling+Complexity+in+the+Heart+of+Software.pdf 英文原版 免費下載AI
- Martin Fowler大神 - 微服務、貧血模型、重構、敏捷開發方法論微服務模型敏捷
- 使用Domain-Driven建立Hypermedia APIAIAPI
- 業務流程模型與資料流程圖的比較 - brcommunity模型流程圖Unity
- [譯文]Domain Driven Design Reference(五)—— 為戰略設計的上下文對映AI
- 第03講:Flink 的程式設計模型與其他框架比較程式設計模型框架
- 運用領域模型——DDD模型
- 如何使用充血模型實現防彈程式碼 - DZone Java模型Java
- 在DDD中建立領域模型模型
- 怎麼理解今年 CV 比較火的擴散模型(DDPM)?模型
- DDD聚合的數學模型 -Thomas Ploch模型
- AI模型對比AI模型
- 【機器學習】第二節-模型評估與選擇-效能度量、方差與偏差、比較檢驗機器學習模型
- DDD模型探索的Whirl pool設計流程模型
- ==與equals比較
- 機器學習引數模型與非引數模型/生成模型與判別模型機器學習模型
- domain-driven-hexagon:領域驅動六邊形的Javascript案例AIGoJavaScript
- SAP ECC 和 S4HANA Material 物料庫存管理的模型比較模型
- Hibernate與mybatis比較MyBatis
- yarn 與 npm 比較YarnNPM
- Vue與React比較VueReact
- Vuex與Redux比較VueRedux
- RecyclerView與ListView比較View
- React與Vue模板使用比較(一、vue模板與React JSX比較)ReactVueJS
- 領域驅動模型DDD(一)——服務拆分策略模型
- 模型驅動設計的構造塊(上)——DDD模型
- 全面對比:天工大模型 vs 紫東太初大模型大模型