貧血模型與充血模型比較 - 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部落格模型
- 領域驅動設計(DDD:Domain-Driven Design)AI
- 領域驅動設計(DDD:Domain-Driven Design)轉AI
- 貧血模型-Martin Fowler 翻譯模型
- 實戰DDD(Domain-Driven Design領域驅動設計)AI
- 聊一聊領域驅動與貧血模型模型
- 讀《實戰DDD(Domain-Driven Design領域驅動設計:Evans DDD)》想到的AI
- OSI模型 與 DOD模型的比較模型
- <實戰DDD(Domain-Driven Design領域驅動設計:Evans DDD)>讀後疑問AI
- 英文DDD培訓線上課程推薦: 從失血模型重構到充血模型模型
- Implementing Domain Driven Design中文版出版AI
- 大家看看我設計的這個關於圖書館借書還書的模型屬於貧血還是充血?模型
- 併發模型比較模型
- DDD中簡單模型比複雜模型更危險模型
- DDD中事件與命令比較事件
- 規則引擎與ML模型的比較 - xLaszlo模型
- Martin Fowler大神 - 微服務、貧血模型、重構、敏捷開發方法論微服務模型敏捷
- 請問沒有複雜邏輯的領域模型和貧血模型有什麼區別?模型
- Nosql 資料管理系統與模型的比較SQL模型
- 元學習:人類與大模型比較建模大模型
- 業務流程模型與資料流程圖的比較 - brcommunity模型流程圖Unity
- DDD深思,物件裝備模型物件模型
- Cassandra 和 HBase的大表模型比較模型
- 使用Domain-Driven建立Hypermedia APIAIAPI
- 運用領域模型——DDD模型
- 第03講:Flink 的程式設計模型與其他框架比較程式設計模型框架
- [譯文]Domain Driven Design Reference(五)—— 為戰略設計的上下文對映AI
- 領域模型驅動設計(DDD)之模型提煉模型
- 在DDD中建立領域模型模型
- 【機器學習】第二節-模型評估與選擇-效能度量、方差與偏差、比較檢驗機器學習模型