内容简介:在这篇文章中使用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 中的内存模型(上):内存模型基础
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
算法心得:高效算法的奥秘(原书第2版)
(美)Henry S. Warren, Jr. / 爱飞翔 / 机械工业出版社 / 2014-3 / 89.00
【编辑推荐】 由在IBM工作50余年的资深计算机专家撰写,Amazon全五星评价,算法领域最有影响力的著作之一 Google公司首席架构师、Jolt大奖得主Hoshua Bloch和Emacs合作创始人、C语言畅销书作者Guy Steele倾情推荐 算法的艺术和数学的智慧在本书中得到了完美体现,书中总结了大量高效、优雅和奇妙的算法,并从数学角度剖析了其背后的原理 【读者评价......一起来看看 《算法心得:高效算法的奥秘(原书第2版)》 这本书的介绍吧!