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

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

内容简介:在这篇文章中使用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的好处吗?


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

查看所有标签

猜你喜欢:

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

模式识别

模式识别

(希)Sergios Theodoridis、(希)Konstantinos Koutroumbas / 电子工业出版社 / 2010-2 / 75.00元

本书全面阐述了模式识别的基础理论、最新方法以及各种应用。模式识别是信息科学和人工智能的重要组成部分,主要应用领域有图像分析、光学字符识别、信道均衡、语言识别和音频分类等。本书在完美地结合当前的理论与实践的基础上,讨论了贝叶斯分类、贝叶斯网络、线性和非线性分类器设计、上下文相关分类、特征生成、特征选取技术、学习理论的基本概念以及聚类概念与算法。与前一版相比,增加了大数据集和高维数据相关的最新算法,这......一起来看看 《模式识别》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试