值与实体对象(域驱动设计)


Answers:


108

归结为本质区别,身份对实体很重要,对价值对象并不重要。例如,某人的姓名是一个值对象。客户实体可能由客户名称(值对象),List <Order> OrderHistory(实体列表)以及默认地址(通常是值对象)组成。客户实体将具有一个ID,每个订单将具有一个ID,但名称不应该;通常,无论如何在对象模型中,地址的身份可能无关紧要。

值对象通常可以表示为不可变对象。更改值对象的一个​​属性实质上会破坏旧对象并创建一个新对象,因为您不像身份那样关注内容。正确地,只要对象的属性与另一个实例的属性相同,则Name上的Equals实例方法将返回“ true”。

但是,更改诸如客户之类的实体的某些属性不会破坏客户。客户实体通常是可变的。身份保持不变(至少在对象持久化之后)。

您可能没有意识到就创建了价值对象。每当您通过创建细粒度的类来表示实体的某个方面时,您都会获得一个值对象。例如,对有效值有一些约束但由更简单的数据类型组成的IPAddress类将是一个值对象。EmailAddress可以是字符串,也可以是具有自己的一组行为的值对象。

即使在数据库中具有标识的项目也很有可能在对象模型中也没有标识。但是最简单的情况是将一些有意义的属性组合在一起。当您可以将Customer.FirstName,Customer.LastName,Customer.MiddleInitial和Customer.Title组合在一起作为Customer.Name时,您可能不想拥有它们。在考虑持久性时,它们可能会成为数据库中的多个字段,但是对象模型不在乎。


未共享的可变对象放在哪里?如果在整个宇宙中仅存在对一个对象的一种引用,则即使该对象是可变的,其身份也将无关紧要。正如我所看到的,如果存在一个可以用来观察状态的状态的事物,那么它就是一个实体,而该状态可以在不使用该引用来更改状态的情况下进行更改。如果事物不依附于外部世界,或者它是不可变的,或者在宇宙中的任何地方仅存在对它的一种引用,那么上述情况就不会发生,而是一种价值。
2014年

诸如之类的东西int[1]可能是未共享的可变值,可共享的不可变值(如果没有保存引用的东西都不会写入该值)或一个实体(如果存在两个或多个引用,并且其中一个可以用来写)可以使用其他值读取的值)。不幸的是,我不知道Java或.NET中没有语言支持来防止封装了可变值的类对象意外地变成实体。
2014年

@supercat,如果您的意思是没有直接的简单支持,那么我会同意,但是我这样做是为了消除对构造函数的公共访问,仅使用静态工厂创建新实例,并通过只读属性限制对状态的所有访问(无设置器) 。
Charles Bretana 2014年

36

由其所有属性共同定义的任何对象都是值对象。如果任何属性发生更改,您将拥有一个值对象的新实例。这就是为什么将值对象定义为不可变的原因。

如果对象没有完全由其所有属性定义,那么将有一部分属性构成对象的身份。其余属性可以更改,而无需重新定义对象。不能将这种对象定义为不可变的。

进行区分的一种更简单的方法是将值对象视为永远不变的静态数据,将实体视为在应用程序中演化的数据。


7

值类型:

  • 值类型本身并不存在,取决于实体类型。
  • 值类型对象属于实体类型对象。
  • 值类型实例的寿命由拥有实体实例的寿命限制。
  • 三种值类型:基本(原始数据类型),复合(地址)和集合(地图,列表,数组)

实体:

  • 实体类型可以自己存在(身份)
  • 实体具有自己的生命周期。它可以独立于任何其他实体存在。
  • 例如:人员,组织,大学,手机,家庭等。每个对象都有自己的身份

与DDD不相关:(
HydTechie,

6

我不知道以下内容是否正确,但是我想说的是,在使用地址对象的情况下,我们希望将其用作值对象而不是实体,因为对实体的更改将反映在所有链接的对象上(例如一个人)。

以这种情况为例:您与其他人一起住在房子里。如果我们将实体用于地址,我会说所有个人对象都链接到一个唯一的地址。如果有人搬出,您想更新他的地址。如果您要更新地址实体的属性,则所有人将拥有不同的地址。对于值对象,我们将无法编辑地址(因为它是不可变的),因此我们将被迫为该人员提供新的地址。

听起来对吗?我必须说,在阅读DDD书之后,我还是对这种差异感到困惑。

更进一步,该如何在数据库中建模?您是否将“地址”对象的所有属性都作为“人”表中的列,还是要创建一个单独的“地址”表,该表也具有唯一的标识符?在后一种情况下,居住在同一所房屋中的人每个人都有一个地址对象的不同实例,但是这些对象除了其ID属性外都是相同的。


1
“以这种情况为例:您与其他人一起住在您的房子里。如果我们将“实体”用作“地址”,那么我会争辩说,所有“人”对象都链接到一个唯一的“地址”。我认为每个人都有自己的Address实例,但他们恰好是相等的(就像他们每个人都可以拥有5美元钞票,但这并不意味着它是同一张钞票)
Prokurors

“但是这并不意味着它是同一张钞票” –我想这取决于是否为钞票分配了其他属性(例如,发射日期,空间的实际位置等);否则它们将是相同的。而且我猜软件也一样:地址是相同还是不同,取决于我们需要/想要考虑的属性。
adrhc

4

地址可以是取决于业务流程的实体或值对象。地址对象可以是快递服务应用程序中的实体,而地址可以是某些其他应用程序中的值对象。在快递申请中,身份对于地址对象很重要


2

我在另一个线程中询问了这个问题,但我仍然感到困惑。我可能将性能考虑因素与数据建模混淆了。在我们的目录应用程序中,客户直到需要时才改变。这听起来很愚蠢-但是客户数据的“读取”次数远远超过了“写入”次数,并且由于许多Web请求都击中了“活动组”对象,因此我不想一次又一次地加载客户。因此,我走了一条通往Customer对象的不变道路-加载,缓存它,并为希望见客户的(多线程)请求的99%提供相同的请求。然后,当客户更改某些内容时,请一位“编辑”创建新客户并使旧客户无效。

我担心的是,如果多个线程看到同一个客户对象并且是可变的,那么当一个线程开始更改时,其他线程就会出现混乱。

我现在的问题是,1)这是否合理,以及2)如何最好地做到这一点,而又无需复制有关该属性的大量代码。


1

Entities和之间的3个区别Value Objects

  • 标识符与结构相等性:实体具有标识符,如果实体具有相同的标识符,则它们是相同的。超出范围的值对象具有结构相等性,当所有字段都相同时,我们认为两个值对象相等。值对象不能具有标识符。

  • 可变性与不变性:价值对象是不变的数据结构,而实体在其生命周期中会发生变化。

  • 寿命:价值对象应属于实体


1

我可以用很简单的一句话说,我们有三种平等:

  • 标识符相等:类具有ID字段,并且将两个对象与其ID字段值进行比较。
  • 引用相等:如果对两个对象的引用在内存中具有相同的地址。
  • 结构相等:如果两个对象的所有成员都匹配,则它们相等。

标识符相等仅指实体,而结构相等仅指值对象。实际上,值对象没有ID,我们可以互换使用它们。此外,值对象必须是不可变的,并且实体可以是可变的,并且值对象在数据库中将没有nay表。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.