根据标题,我有以下课程:
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中的实体进行引用,但我不确定调用操作的规则是什么。
对于它的价值,下面是我的实际模型的图表(点击here表示完整尺寸)。 ContactList
包含有关如何管理所有类型的联系人(人员/业务位置)的规则,例如删除主要联系人时会发生的情况。它还解决了RavenDB如何存储嵌套实体的一些注意事项(基本上我们需要提供自己的Id策略 - 因此LastContactId属性)。
答案 0 :(得分:2)
首先,这完全取决于上下文,我认为公司确实是特定情境的AR。在其他环境中,同一公司可以是一个简单的对象。现在,我不喜欢教条式地使用规则和模式,因此“规则”所说的并不重要。
在这种情况下,我不会公开地址,因为它似乎是公司内部的。作为公司的共同人,我想要它的主要地址,我不在乎你是否正在使用AddresBook来组织它们。
举一个不太常见的例子:AR Human有两个Eye对象。你是否会要求该人给他的一只眼睛,以便你可以检查他们的颜色,或者你直接询问他的眼睛是什么颜色?
答案 1 :(得分:1)
根据聚合模式:
可以传递对内部成员的瞬时引用,仅在单个操作中使用。
含义 - 公司可以将对其Address对象的引用传递给聚合之外的其他对象,但Address不能是聚合之外的任何其他对象的成员。
例如,对象用户可以询问公司的地址引用,但用户不能将地址作为其成员之一。
为什么这么重要?
因为root控制访问权限,所以不能通过更改内部来瞎了。
如果一个对象用户将地址作为其成员之一,它可能会在没有公司的情况下将其从数据库中删除,因此公司会因其内部变更而瞎了。
请参阅我写过的post,其中我演示了为什么这个原则如此重要。
答案 2 :(得分:1)
好问题,这是我一直难以在DDD中找到的事情之一 - 您是否总是通过其聚合根访问实体,并且可能在某些时候违反Law of Demeter(AggregateRoot.EntityX。 EntityY.DoStuff())?你是否缩短了聚合根?您是否在聚合根级别为要访问的每个子实体添加一个直接访问者,使聚合根混乱?
解决这个问题的一种方法可能是:尝试让每个对象只与其直接或附近的邻居交谈,而不是与某些遥远的陌生人交谈。使用多个对象,每个对象都知道从聚合根到您要访问的最终实体的路径的一小部分。
第一个对象只知道聚合根
它将AggregateRoot.SubEntity1注入第二个对象,
第二个对象又将SubEntity1.SubEntity2注入第三个对象
依此类推。
有趣的是,这揭示了一些域实体的(ir)相关性。在地址示例中,问问自己是否适合每个想要访问公司主要地址的对象注入AddressBook。如果它似乎太复杂,也许你不应该首先拥有一个AddressBook。也许这不是一个强烈的概念,它毕竟应该成为无处不在的语言的一部分。
或者,也许你会发现一个AddressBook恰好是你的客户端对象使用的正确对象,并且这个客户端对象在操作公司和地址时一次尝试做太多事情。 / p>