DDD010-领域驱动设计:实体、价值对象以及如何区分它们
DDD 可分为战略和战术设计,其中战术设计是关于 DDD 的构建基块的。这篇文章将是关于DDD的基本构建基块:***实体和价值对象(VOs)。***实体和 VO 是 DDD 中表示模型的两个构建基块。它们是域驱动设计(服务和域事件除外)的起点。
除了只看实体和VO的定义,我还将为您提供一些如何区分它们的指导。
DDD 的构建块
在本章中,我将解释实体和 VO 的概念。DDD 中有更多的构建基块,如服务和域事件(见上图),但它们将超出此帖子的范围。
实体
埃里克 · 埃文斯在 Ddd 书中介绍了实体:
许多对象不是由它们的属性来根本定义的,而是由连续性和身份的线索来定义的。
这句话已经介绍了实体的主要特征:连续性(也通常被称为有生命周期)和身份。
主要由其身份定义的对象称为实体。
当你想到一个实体时,想象一些需要随着时间推移而跟踪,其属性可能会随着时间而改变的东西。为了能够跟踪某物,您需要一种识别对象的方法,并在时间流逝后回答"这是同一个对象吗?一个非常强大的指标的东西是一个实体的东西是像属性(如,或)或属性前缀喜欢或。status``pending``active``inactive``current``last
即使不同对象的属性相同,也必须对对象进行区分。考虑一个申请,管理学生在大学注册不同的课程。A 将是同一个学生,如果属性喜欢,甚至改变。定义学生成为同一个学生意味着什么非常重要。也许这将是类似或只是一个通用的东西。下图显示了此应用程序的潜在类图,从现在起,我将以此为示例使用。Student``email``name``matriculationNumber``id
这可能是实体实际实例的数据库表示*(简单来说,课程
承诺,因为它并不真正需要证明我的观点以后)*:Student
您必须从域的角度回答**“是什么使对象成为同**一对象?因此,定义实体的身份需要了解该域。
警惕要求按属性匹配对象的要求。
这意味着像"如果属性相同,对象应该是相同的"这样的要求是一个强有力的指标,表明它可能根本不是一个实体。
实体也被称为**“参考对象**"。我喜欢这个术语,因为我脑子里有一个图像,指头(箭头)随着时间推移引用了同一个对象。
(在 JPA 中,注释用于实体。@Entity
值对象 (VOs)
许多对象没有概念性。这些对象描述了一个事物的一些特征。
VO 没有身份。它们由属性而不是标识符定义。您可以将 VOs 视为实体的复杂属性。
表示没有概念标识的域的描述性方面的对象称为值对象。价值对象被刻例化,以表示我们只关心它们*是什么*,而不是它们是谁或是谁的设计元素。
回想实体部分的学生示例。可以有一个,其中包括,和。在我们的应用程序领域, 地址将是一个 Vo 。更改其中一个属性将使它成为一个不同的地址。地址更像是一个复杂的属性类型(而不是原始数据类型,如字符串、酒类等)**实体(或其他 VO;**在此情况下为实体)。Student``Address``street``streetNumber``postcode``city``Student
不关心对象的身份让我们可以自由地简化设计并优化性能。我们现在可以共享 VOs 实例,因为它们本质上就像一个持有某些信息的复杂属性。但要做到这一点**,VO必须是不变的**。更改 VOs 属性必须导致创建新实例,而不是修改现有实例。
再次,回到学生的例子。想起住在同一地址的两个学生。他们可以共享 VO 的相同实例,但如果其中一个学生移动到其他地方,我们不想改变该实例,因为这也会影响其他学生。相反,我们最终创建了一个新实例(或重复使用该地址的现有实例(如果它存在)。共享 VO 实例显示在下一张图像中。它还展示了 VO 就像一个复杂的属性,因为它最终在在这种情况下的数据库中的同一行。Address``Address
不要将人工 ID 连接到 VO. VO 也不会在数据库中自己的表中表示。如果你这样做,你不仅会失去性能的好处和较低的复杂性,但你也会混淆模型,使迫使所有对象进入相同的模具。
由于 VOs 的上述好处,您应该将 VO 作为默认值,并且仅在需要时将身份分配给某物(因此使其成为实体)。
(在 JPA 中,注释 (1:1) 和 (1:n) 用于 VOs。@Embeddable``@ElementCollection
区分实体和价值对象
这篇文章侧重于实体和 Vos, 因为它们是相似的, 但不同。我经常问自己的一个问题:“这是实体还是价值对象?两者都是对实际数据进行建模,并且通常都持续在数据库中。但正如我们已经了解到的,实体和 VOs 存在差异。
下表展示了实体和价值对象之间的主要区别:
以下问题可以帮助识别实体或 VO:
*我可以用具有相同属性的另一个对象替换对象吗?*
**如果答案是肯定的,则它是一个值对象。**如前所述,VOs 就像一个复杂的数据类型。您也可以将原始数据类型视为 VO 的整数。那么,你的对象是不是像整数?
*我必须随着时间的推移跟踪一些事情吗?*
**如果答案是,则它是一个实体。**允许跟踪信息的实体。而 Vos 就像时间点的快照。
⚠️**如果某样东西是实体或 VO 取决于您的域。 *它可能是一个域内的实体,而另一个域中的 VO。因此,诸如"地址是价值对象"之类的陈述完全是错误的。一个例子可能是钱。在电子商务中,应用程序资金将像 VO 一样,因为它只代表购买某些东西的能力。100 美元是 100 美元。但是,在处理银行抢劫案时,您可能确实关心特定的钞票及其序列号,以独特的身份识别它。*(我想你🤪得到这个想法)
结论
实体和值对象是 DDD 的几个构建基块中的两个,它们属于 DDD 的战术设计部分。他们都有存储信息的目的,而且大多数情况下,它们最终被存入数据库,但存在差异,我指出。价值对象应该是您的选择,因为它们不那么复杂,并允许更好的性能。如果您需要身份概念,请与实体一起去。
- 原文作者:知识铺
- 原文链接:https://geek.zshipu.com/post/DDD/DDD010-%E9%A2%86%E5%9F%9F%E9%A9%B1%E5%8A%A8%E8%AE%BE%E8%AE%A1%E5%AE%9E%E4%BD%93%E4%BB%B7%E5%80%BC%E5%AF%B9%E8%B1%A1%E4%BB%A5%E5%8F%8A%E5%A6%82%E4%BD%95%E5%8C%BA%E5%88%86%E5%AE%83%E4%BB%AC/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com