内容简介:在这篇文章中使用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 中的内存模型(上):内存模型基础
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Agile Web Application Development with Yii 1.1 and PHP5
Jeffrey Winesett / Packt Publishing / 2010-08-27
In order to understand the framework in the context of a real-world application, we need to build something that will more closely resemble the types of applications web developers actually have to bu......一起来看看 《Agile Web Application Development with Yii 1.1 and PHP5》 这本书的介绍吧!