DDD 聚合和值对象

发布于 2024-12-05 23:07:10 字数 156 浏览 2 评论 0原文

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

谢谢

I'd like to ask question about DDD features. Lets say we have two aggregates and each of them contains value-object Address. Accordingly to Eric Evans DDD, we should isolate aggregates from each other, so aggregate root of first aggregate can't have a link to Address. Frankly, it doesn't seem to make sense for me, so question is how to resolve such situation? Which aggregate should contain Address?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

百变从容 2024-12-12 23:07:11

聚合只关心数据修改。不允许两个聚合修改相同的数据。由于值对象是不可变的,因此它可以防止这种情况发生。因此,两个或多个聚合共享相同的值对象是完全可以的,因为它是只读数据结构,并且聚合不关心读取模型。

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)

对于地址来说,上述情况永远不会发生,因此共享并不危险,因为您对人员地址所做的任何操作都不会影响信件,因此信件仍然保护它自己的不变量。

如果将地址制成实体,那么您将无法在两个实体中使用相同的地址,因为上述代码会使字母容易受到对人员执行的更改的影响,这会打破边界,并且会阻止字母从控制它的不变量。

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


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

对于您需要的运输来说:

Address
{
    Number;
    Unit;
    Street;
    State;
    Country;
    PostalCode;
}

但是对于您需要的位置:

Address
{
    Number;
    Unit;
    Latitude;
    Longitude;
}

DDD 会说,将它们都称为地址,但将它们绑定到不同的上下文。因此,即使在语言中它们都被称为地址,但它们的具体数据和行为可能会根据您所讨论的上下文而有所不同。您绝对不能做的是创建一种 MonsterAdres,它将包含域中所有上下文的所有可能数据和行为,并将其作为所有上下文中使用的地址类型。

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

Aggregates are only concerned with DATA MODIFICATION. No two aggregate should be allowed to modify the same data. Since a Value Object is immutable, it prevents this scenario from ever happening. Therefore it is totally fine for two or more aggregates to share the same Value Object as it is a read only data structure and an Aggregate does not care about the read model.

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)

The above will never happen for Address, and so it's not dangerous to share, because nothing you do to the Address of person will ever have an effect on letter, so letter is still protecting it's own invariants.

If Address is made into an entity, then you wouldn't be able to use the same Address in both Entities, since the above code would make letter vulnerable to changes performed on person, and that would break the boundary, and it would prevent letter from being in control of it's invariants.

This is the whole point of Aggregate Roots, it's too model things in a way that limit side effects. If you define very clear modification boundaries, the code will be easier to work with and you'll prevent potential harmful unexpected impact.


I'll add one more thing. As it was mentioned in another answer, you want different Bounded Context to have a different Address type. The reason for that is that the details you need of an Address in one context are not necessarily the same as what you need in another. So by having two Address type, one for each context, you isolate the needs of one from the needs of the other.

Say for shipping you need:

Address
{
    Number;
    Unit;
    Street;
    State;
    Country;
    PostalCode;
}

But for location you need:

Address
{
    Number;
    Unit;
    Latitude;
    Longitude;
}

DDD will say, call them both Address, but bound them to different context. So even though in the language they are all talked about as an Address, their specific data and behavior might be different based on the context you are talking about. What you must absolutely not do is create a kind of MonsterAddres that would contain all possible data and behavior of all contexts in your domain and have this be the Address type used in all contexts.

Note that, we are talking about the model in your application, it's ok to store all data of addresses in a Monster Address Table, but when modeling your App, you should separate that into logical bounded context that maps to your domain and the ubiquitous language it employs.

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

对于大多数人来说,实体与值对象的担忧归结为人们对数据重复的问题。我们已经接受过训练,能够以单一规范模型的第三范式进行思考。 DDD 通过在需要的地方强制重复并允许曾经被认为是合一的概念来对抗不可避免的复杂性。

希望这有帮助

You could have it using the same value object. But only do this if the aggregate roots exist in the same bounded context and hence has the same meaning for both aggregates. If the aggregates exist in different bounded contexts, then have 2 separate ones and duplicate. Leaking one bounded context's concerns into another is what Eric is trying to fight.

To most, the concerns of entity vs. value object boil down to people having issues with duplication of data. We have been so trained to think in 3rd normal form of a single canonical model. DDD fights the inevitable complexity that that brings by forcing duplication where it's needed and allowing concepts that were once thought to be one into many.

Hope this helps

飘过的浮云 2024-12-12 23:07:10

值对象是描述某些特征或
属性但没有身份概念。

由于它没有概念标识,因此您无法“引用”或“链接”它。你只能‘遏制’它。假设您有一个用户并且用户有年龄。年龄是一个价值对象。如果 John 是 25 岁,Jane 也是 25 岁,那么他们不会“引用”相同的年龄。约翰的年龄与简的年龄完全相等。因此,如果您的地址确实是一个值对象,那么您就没有违反任何聚合边界。您的聚合根只是具有相同的地址。即使您在技术上有对 Address 的 java/c# 引用也没关系,因为值对象在大多数情况下是不可变的。

尽管不知道您正在研究哪个领域,但很难回答您的问题。但一般来说,地址不一定是值对象。 Eric Evans 在他的书中提到邮政服务和投递路线域将处理地址作为一个实体。派出技术人员的电力公司需要认识到,来自“123 Elm St”的两个服务电话实际上来自同一地址,并且只需要派出一名技术人员。在这种情况下,地址或“住宅”是一个实体。

A Value Object is an object that describes some characteristic or
attribute but carries no concept of identity.

Since it does not have conceptual identity you can not 'reference' or 'have link' to it. You can only 'contain' it. Let's say you have a User and user has Age. Age is a value object. If John is 25 years old and Jane is also 25 they do not 'reference' the same Age. Jonh's Age is simply equal to Jane's Age. So if your Address is indeed a Value Object then you are not violating any Aggregate boundaries. Your aggregate roots simply have equal addresses. Even if you technically have java/c# reference to Address it does not matter because Value Object are immutable most of the time.

It is hard to answer your question though without knowing what domain you are working on. But generally Address does not necessarily have to be a Value Object. Eric Evans mentions in his book that Postal Service and Delivery Route domains will treat Address as an Entity. Electrical Company that sends out technicians need to realize that two service calls from '123 Elm St' are actually coming from the same address and it only needs to send one technician. Address or 'Dwelling' is an Entity in this case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文