【发布时间】:2020-07-17 20:44:05
【问题描述】:
我正在研究领域驱动设计的实现,其中我们在同一个聚合中的一些操作需要与其他操作一起发生。这两个操作彼此无关。
这是一个示例代码。
请注意,此代码仅用于说明目的,并非真实示例。
public ProcessOrderCommandHandler : IHandler<ProcessOrderCommand>
{
public async Task Handle(ProcessOrderCommand orderCommand)
{
var order = _repository.LoadOrder(orderCommand.Id);
// Operation - 1
order.AddToCart(orderCommand.Item);
// Operation - 2
order.ProcessOrder();
}
}
public class Order : Aggregate
{
public void AddToCart(Item item)
{ ... }
public void ProcessOrder()
{ ... }
}
ProcessOrder 和AddToCart 操作不相关,我有很多这样的CommandHandlers,它们相互独立,但仍需要结合调用。
我看到有三个选项可以解决这个问题:
-
选项1:以上示例代码。
我不是特别喜欢这个选项,因为我们需要在单个
CommandHandler中调用多个域操作。 -
选项 2:更新域操作以在单个方法调用中执行两个操作,如下所示
public ProcessOrderCommandHandler: IHandler<ProcessOrderCommand> { public async Task Handle(ProcessOrderCommand orderCommand) { var order = _repository.LoadOrder(orderCommand.Id); order.AddToCartAndProcessOrder(orderCommand.Item); } } public class Order : Aggregate { public void AddToCartAndProcessOrder(Item item) { AddToCart(item); ProcessOrder(); } private void AddToCart(Item item) { ... } private void ProcessOrder() { ... } }
同样,如果这是正确的方法,也不是 100% 方便,因为我需要在所有相关操作中这样做。
-
选项 3:引发和处理域事件
public ProcessOrderCommandHandler : IHandler<ProcessOrderCommand> { public async Task Handle(ProcessOrderCommand orderCommand) { var order = _repository.LoadOrder(orderCommand.Id); // Operation - 1 order.AddToCart(orderCommand.Item); } } public class Order : Aggregate { public void AddToCart(Item item) { ... AddDomainEvent(new OrderUpdated(id)); } public void ProcessOrder() { ... } } public OrderUpdatedEventHandler : IDomainEventHandler<OrderUpdatedEvent> { public async Task Handle(OrderUpdatedEvent orderUpdatedEvent) { // Loads the same order object from Cache var order = _repository.LoadOrder(orderUpdatedEvent.Id); // Operation - 2 order.ProcessOrder(); } }
我觉得这种方法是所有方法中最干净的,因为它有助于保持关注点分离。 但是,在这里,我通过 Domain-Event 处理同一聚合中的两个域操作,这不是通常使用 Domain-Events 的方式。根据来自 Microsoft Docs 的域事件definition:
使用领域事件显式实现更改的副作用 在您的域内。
换句话说,使用 DDD 术语,使用领域事件显式地 跨多个聚合实现副作用。
问题:选项 3 是领域驱动设计中可接受的解决方案吗?
-
如果是,您能否分享一些在同一聚合中处理领域事件的参考资料/链接?
-
如果没有,我还有哪些其他选择,包括但不限于选项 1 和 2?
【问题讨论】:
-
我不同意这个定义。领域事件没有任何迹象表明它们不应该完全在您的领域模型中使用,甚至不应该在单个聚合中使用。