DDD:聚合是否可以获取其他聚合作为参数?
DDD: Can aggregates get other aggregates as parameters?
假设我有两个聚合:车辆和司机,并且我有一个规则,如果 driver 正在休假,则不能将车辆分配给 driver。
所以,我的实现是:
class Vehicle {
public void assignDriver(driver Driver) {
if (driver.isInVacation()){
throw new Exception();
}
// ....
}
}
是否可以将聚合作为参数传递给另一个聚合?我做错了什么吗?
一般来说,聚合应该保留自己的边界(为了避免数据加载问题和事务范围问题,例如检查 this 页面),因此只能通过身份引用另一个聚合,例如assignDriver(id guid).
这意味着您必须在调用 assignDriver 之前查询驱动程序,以便执行验证检查:
class MyAppService {
public void execute() {
// Get driver...
if (driver.isInVacation()){
throw new Exception();
}
// Get vehicle...
vehicle.assignDriver(driver.id);
}
}
我会说你的设计是完全有效的并且很好地反映了通用语言。实施 Domain-Driven 设计书中有几个示例,其中一个 AR 作为参数传递给另一个 AR。
例如
Forum#moderatePost:Post
不仅提供给Forum
,还被它修改。
Group#addUser:已提供 User
,但已翻译为 GroupMember
。
如果你真的想解耦,你也可以做类似 vehicule.assignDriver(driver.id(), driver.isInVacation())
的事情,或者引入某种中间 VO,它只保存来自 Driver
的必要状态来做出分配决定。
但是请注意,使用外部数据做出的任何决定都被认为是陈旧的。例如,如果 driver 在分配给车辆后立即去度假会怎样?
在这种情况下,您可能希望使用异常报告(例如,列出所有不可用 driver 的车辆),标记 driver re-assignation 的车辆等。最终一致性可能通过批处理或消息传递(事件处理)完成。
您还可以通过颠倒关系来制定规则 strongly-consistent,其中 Driver
保留它驱动的一组 vehiculeId
。然后您可以使用 DB 唯一约束来确保同一车辆没有超过 1 driver 分配。您还可以违反每笔交易仅修改 1 个 AR 的规则,并对双向关系建模以保护模型中的两个不变量。
但是,我建议您在这里考虑一下现实世界的情况。我怀疑您能否阻止 driver 消失。该系统必须反映现实世界,这可能是该场景的记录簿,这意味着您可以通过强一致性做的最好的事情可能是在他离开时从所有车辆中取消分配 driver。在那种情况下,在同一个 TX 中立即取消分配车辆真的很重要,还是可以接受延迟?
假设您在 micro-services 架构中,
你有一个 'Driver Management' 服务和一个 'Assignation Service' 并且除了技术库之外你没有在两者之间共享代码。
对于 'Driver',您自然会有 2 类,
'Driver Management' 中的聚合,它将保存管理 driver 状态的操作。
而 'Assignation Service' 中的值 object 将只包含分配的相关信息。
当你在一个单一的代码库中时,这种分离更难see/achieve
我也同意@plalx,规则的执行还有更多的意义,而不仅仅是对创建的检查,为此您可以实施他建议的解决方案。
我鼓励您在事件中思考,在以下情况下会发生什么:
- a driver 已安排假期
- 他休假回来的时候
- 如果他更改休假日期
您是否探索过为分配创建聚合?
假设我有两个聚合:车辆和司机,并且我有一个规则,如果 driver 正在休假,则不能将车辆分配给 driver。
所以,我的实现是:
class Vehicle {
public void assignDriver(driver Driver) {
if (driver.isInVacation()){
throw new Exception();
}
// ....
}
}
是否可以将聚合作为参数传递给另一个聚合?我做错了什么吗?
一般来说,聚合应该保留自己的边界(为了避免数据加载问题和事务范围问题,例如检查 this 页面),因此只能通过身份引用另一个聚合,例如assignDriver(id guid).
这意味着您必须在调用 assignDriver 之前查询驱动程序,以便执行验证检查:
class MyAppService {
public void execute() {
// Get driver...
if (driver.isInVacation()){
throw new Exception();
}
// Get vehicle...
vehicle.assignDriver(driver.id);
}
}
我会说你的设计是完全有效的并且很好地反映了通用语言。实施 Domain-Driven 设计书中有几个示例,其中一个 AR 作为参数传递给另一个 AR。
例如
Forum#moderatePost:
Post
不仅提供给Forum
,还被它修改。Group#addUser:已提供
User
,但已翻译为GroupMember
。
如果你真的想解耦,你也可以做类似 vehicule.assignDriver(driver.id(), driver.isInVacation())
的事情,或者引入某种中间 VO,它只保存来自 Driver
的必要状态来做出分配决定。
但是请注意,使用外部数据做出的任何决定都被认为是陈旧的。例如,如果 driver 在分配给车辆后立即去度假会怎样?
在这种情况下,您可能希望使用异常报告(例如,列出所有不可用 driver 的车辆),标记 driver re-assignation 的车辆等。最终一致性可能通过批处理或消息传递(事件处理)完成。
您还可以通过颠倒关系来制定规则 strongly-consistent,其中 Driver
保留它驱动的一组 vehiculeId
。然后您可以使用 DB 唯一约束来确保同一车辆没有超过 1 driver 分配。您还可以违反每笔交易仅修改 1 个 AR 的规则,并对双向关系建模以保护模型中的两个不变量。
但是,我建议您在这里考虑一下现实世界的情况。我怀疑您能否阻止 driver 消失。该系统必须反映现实世界,这可能是该场景的记录簿,这意味着您可以通过强一致性做的最好的事情可能是在他离开时从所有车辆中取消分配 driver。在那种情况下,在同一个 TX 中立即取消分配车辆真的很重要,还是可以接受延迟?
假设您在 micro-services 架构中, 你有一个 'Driver Management' 服务和一个 'Assignation Service' 并且除了技术库之外你没有在两者之间共享代码。 对于 'Driver',您自然会有 2 类, 'Driver Management' 中的聚合,它将保存管理 driver 状态的操作。 而 'Assignation Service' 中的值 object 将只包含分配的相关信息。 当你在一个单一的代码库中时,这种分离更难see/achieve
我也同意@plalx,规则的执行还有更多的意义,而不仅仅是对创建的检查,为此您可以实施他建议的解决方案。 我鼓励您在事件中思考,在以下情况下会发生什么:
- a driver 已安排假期
- 他休假回来的时候
- 如果他更改休假日期
您是否探索过为分配创建聚合?