我可以在聚合根中的实体上调用操作吗?

时间:2012-04-16 20:41:15

标签: domain-driven-design

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

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属性)。

Client Model

3 个答案:

答案 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>