以下示例不遵循LoD:
// This class has to be aware of too many other classes, increasing complexity. class Thing { void foo(Customer c, Employee e, System s, Company c, SupportTicket st) { // Th } } // This function likewise has to be aware of too many other classes. void foo(SupportTicket st) { st.employee().division().incrementResolutionCount(); }
我正在研究一个在数据之间有很多复杂关系的系统.在SQL数据库中,使用四个不同的连接执行查询以获取我想要的数据很容易.但是,在这种情况下,您正在加载基于它实际上不包含的属性的聚合.如果Repository是内存中集合的抽象(即,在最简单的用例中围绕数组的包装),那么纯粹的内存中集合就不可能执行这样的查询,因为没有聚合将匹配它.
我想到的解决方案是你在聚合之间复制数据,而不仅仅是在有界上下文之间(http://www.infoq.com/news/2014/11/sharing-data-bounded-contexts).这增加了对Demeter法的一致性,同时允许您根据自然“属于”相关聚合的属性查询聚合.
这种方法是推荐的吗?
Is this approach recommended?
不是我见过的任何当局.
The solution I’ve thought up is that you duplicate data between aggregates
这对你的记录册意味着什么?
域模型的动机是保持记录簿的完整性,确保它始终满足您的业务不变性.聚合边界描述了域内可以彼此独立更新的不相交区域 – 也就是说每个聚合都是对其自身状态的主权.
因此,当您提出一种在两个聚合体之间复制数据的设计时,您真正断言的是,您的记录簿中的一个事实实际上是两个可能彼此独立发展的不同事实.
这可能是愚蠢的,或者可能是对业务的重要见解.一般来说,不可能争论;您必须与您的域专家坐下来并将其哈希.
但是,我认为,违反德米特定律但实际上正确描述业务的域模型远远优于满足德米特定律但产生误导性业务描述的替代设计.
也就是说,有理由认为您的解决方案违反了LoD,并在此基础上推迟了您的要求:与您的领域专家坐下来,探索无处不在的语言,并让每个人都在同一页面上了解业务是否真的如此这很复杂,如果应该的话.
I am working on a system with a lot of complex relationships between data. In an SQL database, it’d be easy to perform a query with four different joins to get the data that I want. However, in such a scenario, you’re loading an aggregate based off properties that it does not actually contain.
除了标识符之外,为什么要加载聚合?
坚持,你说…
you’re loading an aggregate based off properties that it does not actually contain.
您是否尝试使用违反Demeter法则的查询来加载聚合?哨子是的,有人完成了.
CQRS模式在这里可能很有用,作为帮助解开实际情况的工具.一些直接的猜测
1)如果您不想修改状态,则不需要聚合.聚合用于强制执行写入的业务约束.如果您的用例正在阅读,那么您需要一个状态的只读表示 – 即投影.
2)如果您正在尝试修改状态,那么您正在处理命令,并且命令消息会寻址特定的处理程序.很难想象一个用例,您将命令发送到聚合,而无法识别该聚合.
另一种可能性是您正在考虑的命令实际上是一个具有订阅者的事件.通常,订阅者不会在域模型中聚合,而是通过将命令分派给聚合来对事件做出反应的流程管理器.
3)你仍有可能在错误的地方绘制了聚合边界.