来自How are Value Objects stored in the database?:
假设公司和个人都有相同的邮件地址。 哪些陈述确实有效?
1.“如果我修改Company.Address,我希望Person.Address自动获取这些更改”
2.“如果我修改Company.Address,则不得影响Person.Address”
如果1为真,则地址应为实体
如果2为真,则Address应为值对象。
在上述模型中,邮件Address
不应该是值对象,因为即使Company
和Person
有相同的邮件,此邮件仍然没有概念身份?
换句话说,如果最初Company
和Person
分享 initial.address@gmail.com ,则会获得新邮件 new.address@gmail。 com ,那么我们可以说邮件地址 initial.address@gmail.com 本身没有改变,而{em}替换了Company
和Person
> new.address@gmail.com ?
因此,据我所知,仅仅Address
被分享的事实不应该足以赋予它个性(即身份)?!
谢谢
答案 0 :(得分:5)
是的,您的理解是正确的。 地址几乎总是一个值对象,因为在大多数域中,地址确实只是一个值。
Company 和 Person 今天具有相同的地址的事实并不意味着如果一个发生变化,另一个也应该改变。如果存在这样的关系,则应通过显式约束建模,而不是通过使 Address 成为实体。
Eric Evans在他关于Domain-Driven Design的优秀书中谈到了这一点,甚至提供了一个具体的例子,其中地址可能是一个实体 - 邮政服务,其域名围绕地址,以及个别地址的身份很重要。答案 1 :(得分:1)
实际上,邮件具有概念身份。问题是您实际上并未对电子邮件地址建模,而是对人员的联系信息和/或公司的联系信息进行建模。 继续讨论这个主题,价值对象与身份对象更像是一种实施决策,而不是“绝对真理”。
您可以使用不可变值对象,当您告诉系统“更改地址a到地址b”时,在人员和公司中搜索地址A的所有实例,并立即更新它们以指向地址b。 (或者你可以只更新其中一个)。
使用非值Contact Contact对象更强大。 用:
Contact Information
{
string email;
}
实际上,您可以让人员和公司指向同一个联系信息对象,因此当您更新其中一个时,您也会更新另一个。或者您可以让每个人指向不同的联系信息对象,因此当您更新其中一个时,您不会修改另一个...
BTW:电子邮件具有概念性身份,因为更改电子邮件地址实际上是谷歌上周给我做的,当时他们将我的电子邮件地址从@ googlemail.com更改为@gmail.com。 ..所以,如果有人为我和我的公司收到了我的电子邮件,只有一个更新只是更改了两个实例,因为在那个时候我的电子邮件地址改变了......如果另一方面,我开始使用不同的电子邮件地址,我的联系信息发生了哪些变化......我的旧电子邮件地址仍然存在并且是相同的。我的建议是使用标识对所有内容进行建模,除非它是一个非常好的域对象,您希望无论出于何种原因(例如数字,字符串等)优化用作值对象。但请记住,这通常是一个实施决策,而不是域名。
答案 2 :(得分:1)
这是一个脱离背景的经典案例。
原始问题(如何将值对象存储在数据库中)并没有质疑模型的有效性,我的例子也不是要强调这些问题。我的回答是关于持久性与实体/ VO 。
我纯粹使用Customer
,Person
和Address
的示例,以便我可以与OP共享相同的无所不在的语言(我没有'有时间想出一个更好的例子。)
我会关注casablanca's关于此问题的建议(upvoted)