1、内容摘要

最近在看DDD领域驱动设计,看到实体(Entity),值对象 (Value Object),以及聚合根(Aggregate Root) 时。对他们的关系有些模糊,不清楚。于是去找了找资料,看到有篇文章写的挺好的,于是分享出来给大家。

2、文章来源

http://www.cnblogs.com/netfocus/archive/2012/02/12/2347938.html 博客园用户名 :netfocus [ http://www.cnblogs.com/netfocus/ ]

3、文章详情

3.1 聚合根、实体、值对象的区别?

  • 从标识的角度:

    聚合根具有全局的唯一标识,而实体只有在聚合内部有唯一的本地标识,值对象没有唯一标识,不存在这个值对象或那个值对象的说法;
  • 从是否只读的角度:

    聚合根除了唯一标识外,其他所有状态信息都理论上可变;实体是可变的;值对象是只读的;
  • 从生命周期的角度:

    聚合根有独立的生命周期,实体的生命周期从属于其所属的聚合,实体完全由其所属的聚合根负责管理维护;值对象无生命周期可言,因为只是一个值;

3.2 聚合根、实体、值对象对象之间如何建立关联?

  • 聚合根到聚合根:通过ID关联;
  • 聚合根到其内部的实体,直接对象引用;
  • 聚合根到值对象,直接对象引用;

    实体对其他对象的引用规则:

    • 能引用其所属聚合内的聚合根、实体、值对象;
    • 能引用外部聚合根,但推荐以ID的方式关联,另外也可以关联某个外部聚合内的实体,但必须是ID关联,否则就出现同一个实体的引用被两个聚合根持有,这是不允许的,一个实体的引用只能被其所属的聚合根持有;

值对象对其他对象的引用规则:只需确保值对象是只读的即可,推荐值对象的所有属性都尽量是值对象;

3.3 如何识别聚合与聚合根?

明确含义: 一个Bounded Context(界定的上下文)可能包含多个聚合,每个聚合都有一个根实体,叫做聚合根;

识别顺序: 先找出哪些实体可能是聚合根,再逐个分析每个聚合根的边界,即该聚合根应该聚合哪些实体或值对象;最后再划分Bounded Context;

聚合边界确定法则: 根据不变性约束规则(Invariant)。不变性规则有两类:1)聚合边界内必须具有哪些信息,如果没有这些信息就不能称为一个有效的聚合;2)聚合内的某些对象的状态必须满足某个业务规则;

例子分析1:订单模型

Order(一 个订单)必须有对应的客户信息,否则就不能称为一个有效的Order;同理,Order对OrderLineItem有不变性约束,Order也必须至少有一个OrderLineItem(一条订单明细),否 则就不能称为一个有效的Order;另外,Order中的任何OrderLineItem的数量都不能为0,否则认为该OrderLineItem是无效 的,同时可以推理出Order也可能是无效的。因为如果允许一个OrderLineItem的数量为0的话,就意味着可能会出现所有 OrderLineItem的数量都为0,这就导致整个Order的总价为0,这是没有任何意义的,是不允许的,从而导致Order无效;所以,必须要求 Order中所有的OrderLineItem的数量都不能为0;那么现在可以确定的是Order必须包含一些OrderLineItem,那么应该是通 过引用的方式还是ID关联的方式来表达这种包含关系呢?这就需要引出另外一个问题,那就是先要分析出是OrderLineItem是否是一个独立的聚合 根。回答了这个问题,那么根据上面的规则就知道应该用对象引用还是用ID关联了。那么OrderLineItem是否是一个独立的聚合根呢?因为聚合根意 味着是某个聚合的根,而聚合有代表着某个上下文边界,而一个上下文边界又代表着某个独立的业务场景,这个业务场景操作的唯一对象总是该上下文边界内的聚合 根。想到这里,我们就可以想想,有没有什么场景是会绕开订单直接对某个订单明细进行操作的。也就是在这种情况下,我们 是以OrderLineItem为主体,完全是在面向OrderLineItem在做业务操作。有这种业务场景吗?没有,我们对 OrderLineItem的所有的操作都是以Order为出发点,我们总是会面向整个Order在做业务操作,比如向Order中增加明细,修改 Order的某个明细对应的商品的购买数量,从Order中移除某个明细,等等类似操作,我们从来不会从OrderlineItem为出发点去执行一些业 务操作;另外,从生命周期的角度去理解,那么OrderLineItem离开Order没有任何存在的意义,也就是说OrderLineItem的生命周 期是从属于Order的。所以,我们可以很确信的回答,OrderLineItem是一个实体。

例子分析2:帖子与回复的模型,做个对比,以便更好地理解。

>不变性分析:帖子和回复之间有不变性规则吗?似乎我们只知道一点是肯定的,那就是帖子和回复之间的关系,1:N的关系;除了这个之外,我们看不到任何其他的 不变性规则。那么这个1:N的对象关系是一种不变性规则吗?不是!首先,一个帖子可以没有任何回复,帖子也不对它的回复有任何规则约束,它甚至都不知道自 己有多少个回复;再次,发表了一个回复和帖子也没有任何关系;其次,发表回复对帖子没有任何改变;从业务场景的角度去分析,我们有发表帖子的场景,有发表 回复的场景。当在发表回复的时候,是以回复为主体的,帖子只是这个回复里所包含的必要信息,用于说明这个回复是对哪个帖子的回复。这些都说明帖子和回复之 间找不出任何不变性约束的规则;因为帖子和回复都有各自独立的业务场景的需要,所以可以很容易理解它们都是独立的聚合根;那也很容易知道该如何建立他们之 间的关联了,但是我们要尽量减少关联,所以只保留回复对帖子的关联即可;帖子没有任何必要去保存一个回复的ID的列表;那么你可能会说,当我删除一个帖子 后,回复应该是没有存在的意义的呀?不对,不是没有存在的意义,而是删除了帖子后导致了回复对帖子的关联信息的缺失,导致数据不一致。这是因为帖子和回复 之间有一种必然的联系(1:N),回复一定会有一个对应的帖子;但是回复有其自己的生命周期,不应该随着帖子的删除而级联删除。这种情况下,如果你删除了 帖子,就导致回复也成为了一条无效的数据;所以,我们绝对不允许删除任何聚合根,因为一旦你删除了聚合根,那就意味着与该聚合根相关的其他任何聚合根都会 有外键引用缺失的问题,会导致整个领域模型数据的不一致;所以,永远都不要删除聚合根;

4、精彩评论

感觉看着要

【转载自netfocus博客】聚合(根)、实体、值对象精炼思考总结的更多相关文章

  1. CSDN如何转载别人的博客

    前言   对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提高,有时候看到特别好的博客想转载下载,但是不能一个字一个字的敲了,这时候我们就想快速转载别人的博客,把别人的博客移到自己的空间 ...

  2. .net c#将数据库数据对象转换为实体值对象

    using System; using System.Data; namespace Sunlib { public static class DataHelper { //将数据库数据对象转换为实体 ...

  3. 五、Abp vNext 基础篇丨博客聚合功能

    介绍 业务篇章先从客户端开始写,另外补充一下我给项目起名的时候没多想起的太随意了,结果后面有些地方命名冲突了需要通过手动using不过问题不大. 开工 应用层 根据第三章分层架构里面讲到的现在我们模型 ...

  4. 解决ASP.NET上传文件大小限制------(转载人家的博客很好用,略作修改)

    解决ASP.NET上传文件大小限制 (2012-06-26 15:18:01) 转载▼ 标签: it   第一种方法,主要适用于IIS6.0版本 一.修改配置Web.Config文件中的httpRun ...

  5. CSDN怎么转载别人的博客

    在参考"如何快速转载CSDN中的博客"后,由于自己不懂html以及markdown相关知识,所以花了一些时间来弄明白怎么转载博客,以下为转载CSDN博客步骤和一些知识小笔记. 参考 ...

  6. CSDN怎么一键转载别人的博客

    在参考"如何快速转载CSDN中的博客"后,由于自己不懂html以及markdown相关知识,所以花了一些时间来弄明白怎么转载博客,以下为转载CSDN博客步骤和一些知识小笔记. 参考 ...

  7. HACMP 学习笔记--转载自wangjialiang-csdn博客

    An41 教程: Ha: 初始阶段的规划最重要 第一部分:概念和模型 Ha 目标:掩盖和消除计划和非计划的宕机 Eliminate SPOF :消除单节点故障, single point of fai ...

  8. CSS3 基础知识[转载minsong的博客]

    CSS3 基础知识1.边框    1.1 圆角  border-radius:5px 0 0 5px;    1.2 阴影  box-shadow:2px 3px 4px 5px rgba(0,0,0 ...

  9. B/S和C/S【转载Jane的博客 http://blog.sina.com.cn/liaojane】

    什么是C/S和B/S结构?         C/S又称Client/Server或客户/服务器模式.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系统,如Oracle.Sybase.In ...

随机推荐

  1. 敏捷开发每日报告--day5

    1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team 2 ...

  2. 20162330 第10周 MySort实验

    关于MySort的进一步实践 课堂作业题目如下: 模拟实现Linux下Sort -t : -k 2的功能.参考Sort的实现.提交码云链接和代码运行截图. import java.util.*; pu ...

  3. fs 创建文件夹

    var http = require("http"); var fs = require("fs"); var server = http.createServ ...

  4. android 广播安装指定下载的apk

    // 广播出去,由广播接收器来处理下载完成的文件   Intent sendIntent = new Intent("com.test.downloadComplete");    ...

  5. 20145237 《Java程序设计》第七周学习总结

    20145237 <Java程序设计>第七周学习总结 教材学习内容总结 第十三章   一.认识时间与日期   1.时间的度量   在正式认识Java提供了哪些时间处理API之前,得先来了解 ...

  6. android之SVG制作与应用

    文章解析及例子:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0825/3362.html 工具:Photoshop CC+sv ...

  7. python 字符串和字典

    一.字符串操作 name = "my name is \t {name} and i am {year} years old" 1.首字母大写 print(name.capital ...

  8. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  9. ASP.NET 访问项目网站以外的目录文件

    简单的说,可以通过在 IIS 添加虚拟目录的方法做到,获取访问路径的时候就用 HttpContext.Current.Server.MapPath("~/xxx"); 的方式. 下 ...

  10. Python Tornado初学笔记之表单与模板(一)

    Tornado中的表单和HTML5中的表单具有相同的用途,同样是用于内容的填写.只是不同的是Tornado中的表单需要传入到后台,然后通过后台进行对模板填充. 模板:是一个允许嵌入Python代码片段 ...