mad*_*ree 6 domain-driven-design
我想问一下有关DDD功能的问题.假设我们有两个聚合,每个聚合都包含值对象地址.因此,对于Eric Evans DDD,我们应该将聚合彼此隔离,因此第一个聚合的聚合根不能具有到Address的链接.坦率地说,这对我来说似乎没有意义,所以问题是如何解决这种情况?哪个聚合应包含地址?
谢谢
Ada*_*ruk 14
您可以使用相同的值对象.但只有当聚合根存在于相同的有界上下文中时才这样做,因此对于两个聚合具有相同的含义.如果聚合存在于不同的有界上下文中,则有2个单独的并且重复.将一个有限的背景问题泄露给另一个是埃里克试图打击的问题.
对大多数人而言,实体与价值对象的关注归结为人们在重复数据方面存在问题.我们受过如此训练,无法以单一规范模型的第三范式进行思考.DDD通过在需要的地方强制复制而带来不可避免的复杂性,并允许曾经被认为是一对多的概念.
希望这可以帮助
值对象是描述某些特征或属性但不包含身份概念的对象.
由于它没有概念身份,因此您无法"引用"或"拥有链接".你只能'包含'它.假设您有用户,用户有年龄.年龄是一个价值对象.如果约翰25岁,简也25岁,他们就不会"引用"相同的年龄.Jonh的年龄与Jane的年龄完全相同.因此,如果您的地址确实是一个价值对象,那么您不会违反任何聚合边界.您的聚合根只有相同的地址.即使你在技术上有java/c#引用它也没关系,因为Value Object在大多数时候都是不可变的.
虽然不知道你在做什么领域,但很难回答你的问题.但通常地址不一定是值对象.Eric Evans在他的书中提到邮政服务和交付路线域将地址视为实体.派出技术人员的电气公司需要意识到来自'123 Elm St'的两个服务电话实际上来自同一地址,它只需要派一名技术人员.在这种情况下,地址或"住宅"是一个实体.
聚合只与数据修改有关。不应允许两个聚合修改相同的数据。由于值对象是不可变的,因此它可以防止这种情况发生。因此,两个或多个聚合共享相同的值对象完全没问题,因为它是只读数据结构,聚合不关心读取模型。
Address a = new Address("1111 ABC Ave.");
person.setAddress(a);
letter.setAddress(a);
person.getAddress().change("2222 XYS Ave.") // THIS IS ILLEGAL SINCE Address is a VO (immutable)
Run Code Online (Sandbox Code Playgroud)
对于 Address 永远不会发生上述情况,因此共享并不危险,因为您对 person 的 Address 所做的任何事情都不会对 letter 产生影响,因此 letter 仍在保护它自己的不变量。
如果 Address 被做成一个实体,那么你就不能在两个实体中使用相同的 Address,因为上面的代码会使 letter 容易受到对 person 执行的更改的影响,这会打破边界,它会阻止 letter从控制它的不变量。
这是 Aggregate Roots 的重点,它以一种限制副作用的方式对事物进行建模。如果您定义非常明确的修改边界,代码将更易于使用,并且您将防止潜在的有害的意外影响。
我再补充一件事。正如在另一个答案中提到的,您希望不同的有界上下文具有不同的地址类型。原因是在一个上下文中您需要的地址的详细信息不一定与您在另一个上下文中需要的相同。因此,通过有两种地址类型,一种用于每个上下文,您可以将一种的需求与另一种的需求隔离开来。
说你需要的运输:
Address
{
Number;
Unit;
Street;
State;
Country;
PostalCode;
}
Run Code Online (Sandbox Code Playgroud)
但是对于位置,您需要:
Address
{
Number;
Unit;
Latitude;
Longitude;
}
Run Code Online (Sandbox Code Playgroud)
DDD 会说,将它们都称为 Address,但将它们绑定到不同的上下文。因此,即使在语言中它们都被称为地址,但它们的具体数据和行为可能会根据您所谈论的上下文而有所不同。您绝对不能做的是创建一种 MonsterAddres,它包含域中所有上下文的所有可能数据和行为,并将其作为所有上下文中使用的 Address 类型。
请注意,我们正在谈论您的应用程序中的模型,可以将所有地址数据存储在 Monster 地址表中,但是在对您的应用程序建模时,您应该将其分离为映射到您的域和无处不在的语言的逻辑有界上下文它使用。