我正在读一本关于DDD的书,我看到一个涉及汽车,发动机,车轮和轮胎的示例域名。
以上是本书中的模型。客户也是聚合根
拥有该模型,可能存在引擎可具有高度,宽度和长度属性的情况
当你需要在小型车上安装大型发动机时会发生什么?引擎无法适应。
如果汽车检查发动机属性并允许它或不成为汽车的一部分,这是一个问题吗?
引擎具有全局标识(就像您知道每个引擎都有一个序列号/制造商号)。也许引擎需要由制造商跟踪。
所以我再问一遍,如果汽车正在使用发动机的属性将其装入内部(允许它或不成为它的一部分),这是一个问题吗?
答案 0 :(得分:2)
如果汽车检查发动机属性并允许它是否成为汽车的一部分,这是一个问题吗?
没有
话虽如此,您的验证可能非常复杂,无法引入域名服务。由于涉及两个聚合,您可以这样做:
car.Fit(engine)
或者这个:
engine.Fit(car)
但是,您可能想要检查汽车模型:)
由于规则会更高级并涉及一些数据,您可能想要引入域服务并可能在对象上使用双重调度:
所以而不是car.Fit(engine)
你可以拥有这个:
car.Fit(engine, IModelServiceImplementation)
在Fit
方法调用中:
if (!IModelServiceImplementation.CanFit(car, engine)) { throw new Exception(); }
该服务可能会加载正确的模型,而是检查引擎。根据域名,甚至可能有修改级别和其他规则来处理。
由于Car
实例不包含实际的Engine
实例,而只包含EngineId
或可能包含某个值对象,因此不会将引擎真正分配给汽车。您仍然可以将引擎实例传递给汽车并让它创建关联,但它认为合适。
'Enrico S.'提出的解决方案可能与对聚合根进行更改的情况更为相关,其中可能没有所有聚合根可用,或者甚至聚合根存在于单独的有界上下文中。即使Car
和Engine
位于不同的BCs中,也可能会以某种方式查询有效性。有些事情对于最终的一致性是好的,但其他事情可能不是。
像往常一样,有很多事情要考虑:)
答案 1 :(得分:1)
来自DDD书,p128:
任何跨越AGGREGATES的规则都不会在任何时候都是最新的。通过事件处理,批处理或其他更新机制,可以在特定时间内解决其他依赖关系。
因此,它实际上取决于Car aggregate的设计:如果它需要与Engine强烈一致,那么Engine应该是Car聚合的一部分。 另一方面,如果它只需要“最终一致性”,您可以将该验证逻辑放在域事件中。
见此Udi Dahan的post