2

根据标题,我有以下课程:

public class Company : AggregateRoot {
    public AddressBook AddressBook { get; set; }
}

public class AddressBook {
    public List<Address> Addresses { get; set; }

    public Address GetPrimaryAddress() {
        return Addresses.FirstOrDefault();
    }
}

我是否可以致电:

company.AddressBook.GetPrimaryAddress();

或者我应该公开一个GetPrimaryAddress()方法Company,然后调用该AddressBook方法?

我知道我不应该引用AggregateRoot 中的实体,但我不确定调用操作的规则是什么。

更新

对于它的价值,下面是我的实际模型的图表(单击此处查看全尺寸) 。包含有关应如何管理所有类型的联系人(个人/业务位置)的规则,例如删除主要联系人时会发生什么。它还解决了一些关于 RavenDB 如何存储嵌套实体的警告(本质上我们需要提供我们自己的 Id 策略 - 因此是 LastContactId 属性)。ContactList

客户模型

4

3 回答 3

2

首先,这完全取决于上下文,我假设 Company 确实是该特定上下文的 AR。同一个公司在其他上下文中可以是一个简单的对象。现在,我不喜欢教条地使用规则和模式,所以“规则”说什么并不重要。

在这种情况下,我不会公开地址,因为它似乎是公司内部的。作为公司的用户,我想要它的主要地址,我不在乎你使用AddresBook来组织它们。

举一个不太常见的例子:AR Human 有两个 Eye 对象。你会要求这个人给他一只眼睛,这样你就可以检查它们的颜色,还是直接问那个人他的眼睛是什么颜色?

于 2012-04-17T12:44:18.960 回答
1

根据聚合模式:

对内部成员的瞬态引用只能在单个操作中使用。

含义 - 公司可以将其地址对象的引用传递给聚合之外的其他对象,但地址不能是聚合之外的任何其他对象的成员。

例如,对象用户可以向公司请求对地址的引用,但用户不能将地址作为其成员之一。

为什么这如此重要?

因为根控制着访问,所以它不会被内部结构的改变弄得措手不及。

如果对象 User 将 Address 作为其成员之一,它可能会在没有其 Company 的情况下将其从数据库中拉出,因此,Company 将对其内部结构的更改措手不及。

请看我写的一篇文章,我在其中展示了为什么这个原则如此重要。

于 2012-04-17T07:16:48.483 回答
1

好问题,这是我在 DDD 中一直难以解决的问题之一 - 你是否总是通过它们的聚合根访问实体,并且在某些时候可能违反了得墨忒耳定律(AggregateRoot.EntityX.EntityY.DoStuff() ) ? 您是否使聚合根短路?您是否在聚合根级别为要访问的每个子子实体添加一个直接访问器,从而混淆聚合根?

解决这个问题的一种方法可能是:尝试让每个对象只与其直接或附近的邻居交谈,而不是与某个遥远的陌生人交谈。使用多个对象,每个对象都知道从聚合根到要访问的最终实体的一小部分路径。

  • 第一个对象只知道聚合根,

  • 它将 AggregateRoot.SubEntity1 注入第二个对象,

  • 第二个对象又将 SubEntity1.SubEntity2 注入到第三个对象中

  • 等等。

有趣的是,这揭示的一件事是您的一些域实体的(不)相关性。在地址示例中,问问自己是否感觉适合每个想要访问公司主要地址的对象都被注入地址簿。如果它看起来太复杂,也许你一开始就不应该有地址簿。也许它毕竟不是一个如此强烈的概念,以至于它应该成为无处不在的语言的一部分。

或者,也许您会发现 AddressBook 正是您的客户端对象使用的正确对象,并且该客户端对象在操作公司和地址时试图一次做太多事情。

于 2012-04-17T11:55:59.570 回答