繁体   English   中英

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

[英]Value vs Entity objects (Domain Driven Design)

我刚刚开始阅读 DDD。 我无法完全掌握实体与值对象的概念。有人可以解释当值对象被设计为实体对象时系统可能面临的问题(可维护性、性能等)吗? 例子会很棒......

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

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

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

您可能在没有意识到的情况下创建了值对象; 任何时候你通过创建一个细粒度的类来表示实体的某些方面,你就有了一个值对象。 例如,一个类 IPAddress 对有效值有一些限制,但由更简单的数据类型组成,将是一个值对象。 EmailAddress 可以是字符串,也可以是具有自己的行为集的值对象。

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

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

如果对象没有完全由其所有属性定义,则存在组成对象标识的属性子集。 其余属性无需重新定义对象即可更改。 这种对象不能在 immutable 中定义。

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

值类型:

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

实体:

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

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

以这种情况为例:您和其他一些人住在自己的房子里。 如果我们将 Entity 用于 Address,我认为所有 Person 对象都链接到一个唯一的 Address。 如果一个人搬出去,你想更新他的地址。 如果您要更新地址实体的属性,则所有人都将拥有不同的地址。 在值对象的情况下,我们将无法编辑地址(因为它是不可变的)并且我们将被迫为该人提供一个新地址。

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

更进一步,这将如何在数据库中建模? 您是否将 Address 对象的所有属性都作为 Person 表中的列,或者您是否会创建一个单独的 Address 表,该表也将具有唯一标识符? 在后一种情况下,住在同一栋房子里的人每个人都有一个不同的 Address 对象实例,但这些对象除了 ID 属性外都是相同的。

地址可以是实体或值对象,这取决于繁忙的进程。 地址对象可以是快递服务应用程序中的实体,但地址可以是其他应用程序中的值对象。 在快递申请中地址对象的身份问题

3 EntitiesValue Objects区别

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

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

  • Lifespan:值对象应该属于实体

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

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

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

用一个非常简单的句子我可以说,我们有三种类型的平等:

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

标识符相等仅指实体,结构相等仅指值对象。 事实上,值对象没有 id,我们可以互换使用它们。 值对象也必须是不可变的,实体可以是可变的,值对象在数据库中不会有表。

一个实体:

  • 有身份

  • 包含值对象

  • 可能包含其他实体

  • 可以是可变的

一个值对象:

  • 没有身份

  • 必须是不可变的

考虑以下来自Wikipedia 的示例,以便更好地理解值对象和实体之间的区别:

价值对象:人们在兑换美元钞票时,一般不区分每张独特的钞票; 他们只关心美元钞票的面值。 在这种情况下,美元钞票是值对象。 但是,美联储可能会关注每张独特的钞票; 在这种情况下,每项法案都是一个实体。

实体:大多数航空公司在每个航班上都唯一区分每个座位。 在这种情况下,每个座位都是一个实体。 但是,西南航空、易捷航空和瑞安航空不区分每个座位; 所有座位都一样。 在这种情况下,座位实际上是一个值对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM