Domain driven design DDD聚合和值对象

Domain driven design DDD聚合和值对象,domain-driven-design,Domain Driven Design,我想问一个关于DDD功能的问题。假设我们有两个聚合,每个聚合都包含值对象地址。根据Eric Evans DDD,我们应该将聚合彼此隔离,这样第一个聚合的聚合根就不能有到地址的链接。坦白地说,这对我来说似乎没有意义,所以问题是如何解决这种情况?哪个聚合应该包含地址 谢谢您可以使用相同的值对象获得它。但只有当聚合根存在于相同的有界上下文中,并且因此对两个聚合具有相同的含义时,才可以这样做。如果聚合存在于不同的有界上下文中,则有两个单独的聚合并重复。将一个有限的上下文的关注点泄露到另一个上下文中是Er

我想问一个关于DDD功能的问题。假设我们有两个聚合,每个聚合都包含值对象地址。根据Eric Evans DDD,我们应该将聚合彼此隔离,这样第一个聚合的聚合根就不能有到地址的链接。坦白地说,这对我来说似乎没有意义,所以问题是如何解决这种情况?哪个聚合应该包含地址


谢谢

您可以使用相同的值对象获得它。但只有当聚合根存在于相同的有界上下文中,并且因此对两个聚合具有相同的含义时,才可以这样做。如果聚合存在于不同的有界上下文中,则有两个单独的聚合并重复。将一个有限的上下文的关注点泄露到另一个上下文中是Eric试图解决的问题

对大多数人来说,实体与价值对象的关系归结为人们对数据重复的问题。我们受过这样的训练,可以用单一规范模型的第三范式来思考。DDD通过在需要的地方强制复制和允许曾经被认为是一对多的概念来对抗不可避免的复杂性

希望这有帮助

值对象是描述某种特征或特性的对象 属性,但不包含身份的概念

因为它没有概念标识,所以不能“引用”或“链接”。你只能“控制”它。假设你有一个用户,用户有年龄。年龄是一个价值对象。如果约翰是25岁,简也是25岁,他们就不会“提及”同一年龄。约翰的年龄与简的年龄完全相等。因此,如果您的地址确实是一个值对象,那么您没有违反任何聚合边界。聚合根的地址完全相同。即使从技术上讲,您有java/c#引用来解决这个问题,但这并不重要,因为值对象在大多数情况下是不可变的


如果你不知道你在做什么,很难回答你的问题。但通常地址不一定必须是值对象。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)
上述情况永远不会发生在地址上,所以分享并不危险,因为你对某人的地址所做的任何事情都不会对信件产生影响,所以信件仍然在保护它自己的不变量

如果将地址设置为一个实体,那么您将无法在两个实体中使用相同的地址,因为上面的代码将使字母容易受到对person执行的更改的影响,这将打破边界,并防止字母控制其不变量

这就是聚合根的全部意义,它以一种限制副作用的方式对事物进行建模。如果您定义了非常明确的修改边界,代码将更易于使用,并且您将防止潜在的有害意外影响


我再补充一件事。正如在另一个答案中提到的,您希望不同的有界上下文具有不同的地址类型。原因是,在一个上下文中,您需要的地址细节不一定与在另一个上下文中需要的地址相同。因此,通过使用两种地址类型,每个上下文一种,您可以将其中一种的需求与另一种的需求隔离开来

对于您需要的装运,请说明:

Address
{
    Number;
    Unit;
    Street;
    State;
    Country;
    PostalCode;
}
Address
{
    Number;
    Unit;
    Latitude;
    Longitude;
}
但对于您需要的位置:

Address
{
    Number;
    Unit;
    Street;
    State;
    Country;
    PostalCode;
}
Address
{
    Number;
    Unit;
    Latitude;
    Longitude;
}
DDD会说,将它们都称为地址,但将它们绑定到不同的上下文。因此,即使在语言中,它们都被称为地址,但它们的具体数据和行为可能会因您所谈论的上下文而有所不同。您绝对不能创建一种MonsterAddress,它包含域中所有上下文的所有可能数据和行为,并使其成为所有上下文中使用的地址类型


请注意,我们讨论的是应用程序中的模型,可以将所有地址数据存储在Monster地址表中,但在对应用程序建模时,您应该将其分为映射到您的域的逻辑有界上下文和它所使用的普遍语言。

您能给出一个有界上下文和无界上下文的示例吗?为了更好地理解。如果您有订单范围内的上下文和客户范围内的上下文,则希望有独立的地址。客户和订单AR在不同的上下文中。如果您有订单和发货信息,则它们位于相同的上下文中,您可以使用相同的地址值对象。