内容简介:在这篇文章中使用Vaughn Vernon的书[ IDDD,2013 ] 的例子来描述SCRUM模型的情景,并能够以实际的方式展示贫血模型和富模型的实现之间的区别。让我们说产品负责人:允许将每个积压项分配给Sprint。如果它已经分配给不同的Sprint,则必须先将其解除分配。分配完成后,通知相关方。
在这篇文章中使用Vaughn Vernon的书[ IDDD,2013 ] 的例子来描述SCRUM模型的情景,并能够以实际的方式展示贫血模型和富模型的实现之间的区别。
让我们说产品负责人:
允许将每个积压项分配给Sprint。如果它已经分配给不同的Sprint,则必须先将其解除分配。分配完成后,通知相关方。
一个非常简单的场景,可以在下面分层显示:
尽管在图中有表示,但我们将在示例中忽略Task。
贫血模型
领域/实体
<b>public</b> <b>class</b> Sprint { <b>public</b> <b>int</b> Id { get; set; } <b>public</b> IList<BacklogItem> BacklogItems { get; set; } <b>public</b> SprintStatusEnum Status { get; set; } <b>public</b> string Description { get; set; } <b>public</b> DateTime BeginDate { get; set; } <b>public</b> DateTime EndDate { get; set; } } <b>public</b> <b>class</b> BacklogItem { <b>public</b> <b>int</b> Id { get; set; } <b>public</b> IList<Task> Tasks { get; set; } <b>public</b> <b>int</b>? Spr<b>int</b>Id { get; set; } <b>public</b> <b>int</b>? UserId { get; set; } <b>public</b> BacklogItemStatusEnum Status { get; set; } <b>public</b> string Description { get; set; } <b>public</b> DateTime? BeginDate { get; set; } <b>public</b> DateTime? EndDate { get; set; } }
领域/服务
<b>public</b> <b>class</b> SprintServices : ISprintServices { <b>private</b> readonly ISprintRepository _sprintRepository; <b>private</b> readonly IBacklogItemRepository _backlogItemRepository; <b>public</b> SprintServices(ISprintRepository sprintRepository, IBacklogItemRepository backlogItemRepository) { _sprintRepository = sprintRepository; _backlogItemRepository = backlogItemRepository; } <b>public</b> <b>void</b> InsertBacklogItem(<b>int</b> spr<b>int</b>Id, <b>int</b> backLogItemId) { <b>var</b> sprint = _sprintRepository.GetById(sprintId); <b>var</b> backLogItem = _backlogItemRepository.GetById(backLogItemId); backLogItem.SprintId = sprintId; backLogItem.Status = BacklogItemStatusEnum.Committed; EmailService.SendMail(<font>"destination@email.com"</font><font>, $</font><font>"The backlog item '{backLogItem.Description}' was assigned to Sprint '{sprint.Description}'"</font><font>); _backlogItemRepository.Update(backLogItem); } } </font>
请注意,它们的实体没有业务逻辑,每个规则都依赖领域服务,实体属性设置没有任何控制,设置这些属性后没有验证,聚合不生成域事件。
这样的对象只是数据容器。
现在看看富血模型......
域/实体
<b>public</b> <b>class</b> Sprint : Entity { <b>public</b> Sprint(string description, DateTime beginDate, DateTime endDate) { Status = SprintStatusEnum.New; Description = description; BeginDate = beginDate; EndDate = endDate; Validate(); } <b>public</b> <b>int</b> Id { get; <b>private</b> set; } <b>public</b> IList<BacklogItem> BacklogItems { get; <b>private</b> set; } <b>public</b> SprintStatusEnum Status { get; <b>private</b> set; } <b>public</b> string Description { get; <b>private</b> set; } <b>public</b> DateTime BeginDate { get; <b>private</b> set; } <b>public</b> DateTime EndDate { get; <b>private</b> set; } <b>public</b> <b>void</b> SetStatus(SprintStatusEnum status) => Status = status; <b>public</b> <b>void</b> SetDescription(string description) => Description = description; <b>public</b> <b>void</b> SetBeginDate(DateTime beginDate) => BeginDate = beginDate; <b>public</b> <b>void</b> SetEndDate(DateTime endDate) => BeginDate = endDate; <b>public</b> <b>void</b> Validate() { <b>if</b> (string.IsNullOrEmpty(Description)) { <b>throw</b> <b>new</b> Exception(<font>"Description can not be null"</font><font>); } <b>if</b> (BeginDate > EndDate) { <b>throw</b> <b>new</b> Exception(</font><font>"EndDate must be greater than BeginDate"</font><font>); } </font><font><i>//more rules...</i></font><font> } } <b>public</b> <b>class</b> BacklogItem : Entity { <b>public</b> BacklogItem(string description) { Status = BacklogItemStatusEnum.New; Description = description; Validate(); } <b>public</b> <b>int</b> Id { get; <b>private</b> set; } <b>public</b> IList<Task> Tasks { get; <b>private</b> set; } <b>public</b> <b>int</b>? Spr<b>int</b>Id { get; <b>private</b> set; } <b>public</b> <b>int</b>? UserId { get; <b>private</b> set; } <b>public</b> BacklogItemStatusEnum Status { get; <b>private</b> set; } <b>public</b> string Description { get; <b>private</b> set; } <b>public</b> DateTime? BeginDate { get; <b>private</b> set; } <b>public</b> DateTime? EndDate { get; <b>private</b> set; } <b>public</b> <b>void</b> SetSpr<b>int</b>Id(<b>int</b>? spr<b>int</b>Id) => Spr<b>int</b>Id = spr<b>int</b>Id; <b>public</b> <b>void</b> SetUserId(<b>int</b>? userId) => UserId = userId; <b>public</b> <b>void</b> SetStatusToNew() => Status = BacklogItemStatusEnum.New; <b>public</b> <b>void</b> SetStatusToCommitted() => Status = BacklogItemStatusEnum.Committed; <b>public</b> <b>void</b> SetStatusToApproved() => Status = BacklogItemStatusEnum.Approved; <b>public</b> <b>void</b> SetStatusToDone() => Status = BacklogItemStatusEnum.Done; <b>public</b> <b>void</b> SetDescription(string description) => Description = description; <b>public</b> <b>void</b> SetBeginDate(DateTime? beginDate) => BeginDate = beginDate; <b>public</b> <b>void</b> SetEndDate(DateTime? endDate) => BeginDate = endDate; <b>public</b> <b>void</b> CommitToSprint(Sprint sprint) { <b>if</b> (IsCommittedToSprint()) { UncommitFromSprint(); } SetStatusToCommitted(); SetSprintId(sprint.Id); <b>this</b>.AddDomainEvent(<b>new</b> BacklogItemCommitted { Id = Id, SprintId = SprintId.Value }); } <b>public</b> <b>void</b> UncommitFromSprint() { SprintId = <b>null</b>; <b>this</b>.AddDomainEvent(<b>new</b> BacklogItemUncommitFromSprint { Id = Id, SprintId = SprintId.Value }); } <b>public</b> bool IsCommittedToSpr<b>int</b>() => Spr<b>int</b>Id != <b>null</b> && Spr<b>int</b>Id != <b>default</b>(<b>int</b>); <b>public</b> <b>void</b> Validate() { <b>if</b> (string.IsNullOrEmpty(Description)) { <b>throw</b> <b>new</b> Exception(</font><font>"Description can not be null"</font><font>); } </font><font><i>//more rules...</i></font><font> } } </font>
应用:
<b>public</b> <b>class</b> BoardApplication : IBoardApplication { <b>private</b> readonly ISprintRepository _sprintRepository; <b>private</b> readonly IBacklogItemRepository _backlogItemRepository; <b>public</b> BoardApplication(ISprintRepository sprintRepository, IBacklogItemRepository backlogItemRepository) { _sprintRepository = sprintRepository; _backlogItemRepository = backlogItemRepository; } <b>public</b> <b>void</b> ToAllocateBacklogItemToaSpr<b>int</b>(<b>int</b> spr<b>int</b>Id, <b>int</b> backLogItemId) { <b>var</b> sprint = _sprintRepository.GetById(sprintId); <b>var</b> backLogItem = _backlogItemRepository.GetById(backLogItemId); backLogItem.CommitToSprint(sprint); _backlogItemRepository.Update(backLogItem); } }
你能看到区别么?
第一个例子使用了一种非常以数据为中心的方法,而不是行为方法。它不是一个真正的领域模型。
在我们的Rich Model示例中,我们使用表达泛在语言的域对象的行为。
它不会向客户端公开数据属性,而是公开一种行为,该行为明确且清楚地表明客户可以将Backlog项目分配给Sprint。
如果不将此丰富的行为插入Backlog项,则客户端必须处理事件,这是非常错误的。
在第二个例子中,好处要大得多。
现在,您能看到使用Rich Model的好处吗?
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 能聊聊你对充血模型和贫血模型的理解吗?
- 能量视角下的GAN模型(三):生成模型=能量模型
- 提高模型准确率:组合模型
- JVM内存模型 与 JMM内存模型
- Golang并发模型:轻松入门流水线模型
- C++11 中的内存模型(上):内存模型基础
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
GitHub入门与实践
[日] 大塚弘记 / 支鹏浩、刘斌 / 人民邮电出版社 / 2015-7 / 39.00元
本书从Git的基本知识和操作方法入手,详细介绍了GitHub的各种功能,GitHub与其他工具或服务的协作,使用GitHub的开发流程以及如何将GitHub引入到企业中。在讲解GitHub的代表功能Pull Request时,本书专门搭建了供各位读者实践的仓库,邀请各位读者进行Pull Request并共同维护。一起来看看 《GitHub入门与实践》 这本书的介绍吧!