消息场景:用户 A 发送一个消息给用户 B,用户 B 回复一个消息给用户 A。。。
现有设计:消息设计为实体并为聚合根,发件人、收件人设计为值对象。
三个问题:
《领域驱动设计》5.2 实体:
摘录一段:许多对象不是由它们的属性来定义,而是通过一系列的 连续性 (continuity)和 标识 (identity)来从根本上定义的。
归纳:
标识在实体中的另一种体现就是 唯一 和 不可变 ,其概念在很多资料中有说明,这也是实体最重要的特性。
我有一个双胞胎哥哥,我们俩出生的时候,长得一模一样,以至于我们的爸妈都分不清,不得已他们在我们脖子上系个项链来标记:谁是老大?谁是老二?其实这个“标记”就可以看作是实体的标识,只不过是用项链来 标识 的,就像我们在项目中使用 GUID 方式一样,目的就是用来 体现标识 ,但不管用什么方式表示,这个标识必须在这个特定环境下唯一,也就是说,我和我双胞胎哥哥的项链不能完全一样,要不然我爸妈就不能 区分 我们俩了。
我和我那双胞胎哥哥就这样一天一天的长大,但出奇的是,我们哥俩越长越像,以至于我们互相看对方,都以为自己在“照镜子”一样,但唯一不变的是我们俩脖子上的项链,这也是区分我们哥俩的唯一方式。刚出生的我和现在的我,脖子上的项链是一样的,这也就是实体标识的 不可变性 ,也就是说刚出生的我和现在的我是同一个人,项链只不过在我成长的过程中起到“ 标记 ”的作用(当然也可以是手带、脚环之类的信物),它会“陪伴”我的一生,这个“陪伴”的过程,可以理解为实体的另一种特性- 连续性 。
有一天,我们镇要统计双胞胎的分布情况,然后调查人员来到我们家,问我们爸妈:“你们家里有没有双胞胎?几对双胞胎?龙凤胎?还是。。。”,然后我爸妈就报上:“一对双胞胎-两个小子”,然后调查人员就做了笔记走了。在这个过程中,他们丝毫没有提及我脖子上的“项链”,虽然它在我爸妈眼里是那么重要(用来标记我们哥俩),但在调查人员眼里却什么都不是,他们只需要知道我和我双胞胎哥哥是什么样的双胞胎就行了,这也就是实体和值对象的根本区别: 实体不仅需要知道它是什么?而且还需要知道它是哪个?而值对象只需要知道它是什么?
特定环境下,实体和值对象的区分例子有很多,比如《领域驱动设计》书中所说的“体育场座位例子”和“ Custorm-Address 例子”等等,但大部分都是强调实体的标识特性,却很少提及连续性,那什么是连续性?这部分内容,在《领域驱动设计》中5.2实体章节中最后部分有提及,但都是零碎的概念性文字,如果不注意的话,很容易会被忽略掉。
摘录一段:只要一个对象在生命周期中能够保持连续性,并且独立于它的属性(即使这些属性对系统用户非常重要),那它就是一个实体。
这个内容可以结合上面我和我双胞胎哥哥的例子进行理解,“项链”会陪伴的我一生,这段话可以拆分对应理解: 项链-标识、一生-生命周期、陪伴-连续性。 也就是说连续性不能理解为生命周期,它应该理解为: 标识在实体生命周期内体现出连续性 。
结合上面实体特性的理解,Message 实体是怎么得来的,就很好理解了,消息场景毫无疑问聚合的是消息,消息实体是怎么得来的?可以换个角度理解:为什么把消息设计为实体?首先看下消息实体符不符合实体的两个特性。
上面的分析说明消息实体符合实体的两个特性,也就是说消息可以设计为实体,至于怎么得来的?可以这样理解,消息场景首先考虑的是消息,就像我们家的双胞胎,首先考虑的是我和我那双胞胎哥哥。
在之前的 一篇博文 中,园友 鼻涕成诗 有这样的疑问:联系人作为值对象这一点有点不太理解,好处是什么?我当时是这样回复的:
联系人作为值对象,因为他不在消息系统中存储,是从外部获取的,而且它的存在要依附于消息,在消息系统这个业务场景中,如果脱离了消息,它就没有什么意义,对于消息而言,我只要知道这个联系人的内容是什么就行了,而不需要它具体什么哪个,人?还是邮箱?这个它并不关心,不是说把联系人作为值对象有什么好处,而是在这个业务场景下,这样设计比较合理些。
回复内容现在看来有些牵强,先不讨论对与错,按照上面消息实体的分析模式,在消息场景下,看下发件人、收件人(可以统称为 联系人 ,发件人和收件人有可能为同一联系人)是否具有实体的一些特性。
在之前的理解中,联系人设计为值对象的想法是,把联系人看作是一个值,一个依附于消息实体的具体值,我只需要知道这个值就行了,具体体现就是 SenderID 或 RecipientID,其实这个就是联系人的标识,只是当时被两点所迷惑:
把联系人设计为值对象当然也有“好处”,比如可以减少对联系人的管理,因为如果联系人设计为值对象,那它就是一个值,也就没有对象的概念,但 出来混的迟早是要还的 ,我要加一个用户禁言功能,这个在现有的设计中就不好进行实现。像这种 依附性实体 的场景也很多,比如购物车应用中的 Order 和 Custorm,Custorm 依附于 Order,这个首先需要明确的是 购物车应用场景 ,如果是其他的场景下,那 Custorm 就不存在依附关系。
我和我双胞胎哥哥出生的时候,在我们的保温箱上,除了需要标明我们两个的”身份“之外,还需要标明我们爸妈的”身份“,具体标识可以用身份证号,这个就像消息实体中的 SenderID、RecipientID 一样,虽然它是一个”值“,但我还需要知道它具体标识的是哪个对象, 因为我不仅需要它表示的值是多少,我还需要知道它所代表的对象是哪个 ,就比如我和我双胞胎哥哥要根据这个身份证号,找到我们的父母一样。
话不言多,总之一句话:发件人、收件人(联系人)需要设计为实体。
消息场景实体和值对象:
概念理解:
如果您有任何想法或问题需要讨论或交流,可进入交流区发表您的想法或问题。
来源: http://www.tuicool.com/articles/vqYnayy