贫血模型与充血模型比较 - DDD - The Domain Driven Design

栏目: 后端 · 发布时间: 6年前

内容简介:在这篇文章中使用Vaughn Vernon的书[ IDDD,2013 ] 的例子来描述SCRUM模型的情景,并能够以实际的方式展示贫血模型和富模型的实现之间的区别。让我们说产品负责人:允许将每个积压项分配给Sprint。如果它已经分配给不同的Sprint,则必须先将其解除分配。分配完成后,通知相关方。

在这篇文章中使用Vaughn Vernon的书[ IDDD,2013 ] 的例子来描述SCRUM模型的情景,并能够以实际的方式展示贫血模型和富模型的实现之间的区别。

让我们说产品负责人:

允许将每个积压项分配给Sprint。如果它已经分配给不同的Sprint,则必须先将其解除分配。分配完成后,通知相关方。

一个非常简单的场景,可以在下面分层显示:

贫血模型与充血模型比较 - DDD - The Domain Driven Design

尽管在图中有表示,但我们将在示例中忽略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的好处吗?


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Application Development with Yii 1.1 and PHP5

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》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具