首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在单个聚合中处理域事件?

在单个聚合中处理域事件?
EN

Stack Overflow用户
提问于 2020-07-17 20:44:05
回答 3查看 768关注 0票数 1

我正在研究一个领域驱动的设计实现,在这个实现中,我们有一些操作在相同的聚合中,需要与其他操作一起进行。这两种操作是互不相关的。

这是一个示例代码。

注意,此代码仅用于说明性目的,而不是实际示例。

代码语言:javascript
复制
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()
     { ... }       
}

ProcessOrderAddToCart操作是不相关的,我有许多这样的CommandHandlers,它们彼此独立,但仍然需要联合调用。

我认为解决这一问题有三种选择:

  • 选项1:上面的示例代码。 我并不特别喜欢这个选项,因为我们需要在单个CommandHandler中调用多个域操作。
  • 选项2:更新域操作以在单个方法调用中执行两个操作,如下所示 公共ProcessOrderCommandHandler: IHandler {公共异步任务句柄(ProcessOrderCommand orderCommand) { var order = _repository.LoadOrder(orderCommand.Id);}私有空AddToCart(项){.}私有空ProcessOrder() {.}}

同样,如果这是正确的方式,也不是100%的方便,因为我需要在所有相关操作中这样做。

  • 选项3:引发和处理域事件 公共ProcessOrderCommandHandler : IHandler {公共异步任务句柄(ProcessOrderCommand orderCommand) { var order = _repository.LoadOrder(orderCommand.Id);// Operation-1 order.AddToCart(orderCommand.Item);}公共类顺序:聚合{公共空AddToCart(项){.AddDomainEvent(新的OrderUpdated(id));}公共void ProcessOrder() {.}公共OrderUpdatedEventHandler : IDomainEventHandler {公共异步任务句柄(OrderUpdatedEvent orderUpdatedEvent) { //从Cache var order =_repository.LoadOrder(orderUpdatedEvent.Id)加载相同的order对象;// Operation-2 order.ProcessOrder();}}

我觉得这种方法是最干净的,因为它有助于保持关注点的分离。但是,在这里,我通过域-事件来处理同一个聚合中的两个域操作,而这并不是域事件通常的使用方式。根据来自Microsoft的域-事件定义

使用域事件显式地实现域内更改的副作用。 换句话说,使用DDD,使用域事件显式地实现跨多个聚合的副作用。

问:在领域驱动设计中,选项3是一个可接受的解决方案吗?

  • 如果是的话,你能分享一些参考资料/链接,其中域事件是在同一个聚合处理吗?
  • 如果没有,我还有哪些其他选择,包括但不限于备选案文1和2?
EN

回答 3

Stack Overflow用户

发布于 2020-07-17 22:03:45

ProcessOrderAddToCart操作是不相关的,我有许多这样的CommandHandlers,它们彼此独立,但仍然需要联合调用。

在直接回答你的问题之前,我建议重新评估这一声明。如果操作不相关,为什么它们属于同一个集合?另外,这些CommandHandlers是否运行在相同的集合上?

简而言之,您确定您的集合是正确的吗?他们应该有一个单一和明确的责任。如果有不相关的操作或太多的操作,它们可能承担多个职责。

现在,关于你的三个选择。在我看来,CommandHandlers被称为清洁架构中的用例。在您的场景中,用例基本上是从DB加载聚合,调用业务操作,并将更新的聚合存储回DB (加上潜在的发布事件、与第三方的对话等)。因此,如果您这样认为,您的用例需要在同一个聚合中调用2个业务操作这一事实并不是一个问题,因为这就是您的用例所指定的。

如果这两个操作没有意义,您可以将这两个操作合并为一个操作。

如果我们假设聚合是正确的,那么选项3是我唯一不会去看的。在我看来,这将是滥用一个模式的东西,它是不打算使用。

但是,如果您认为,实际上,这些操作属于不同的聚合,那么使用事件肯定是最好的选择。

考虑以下要求:

  1. 当用户单击“添加到购物车”时,应将选定的产品添加到购物车中。
  2. 将产品添加到购物车时,应重新计算运费

在这个场景中,您显然有两个聚合(购物车和船运)。添加到Cart和重新计算航运成本是两个独立的操作,它们与事件协调更有意义,并与业务规范保持一致(“当X发生时.”)。

现在考虑上一个示例的另一个用例:

  1. 在更新运输地址时,应重新计算运费。

现在,更新航运地址和重新计算运输成本是在同一个聚合上的两个操作,但在这种情况下,将它们与用例分开调用是没有意义的,因为更改地址而不重新计算成本将使聚合处于不一致的状态,因此聚合本身可以在地址更改后立即自动重新计算成本。

票数 3
EN

Stack Overflow用户

发布于 2020-07-19 07:34:56

ProcessOrder()方法是否只反映在同一个聚合上执行的聚合内部的更改,以便在向购物车中添加某些项时作出反应?如果是,我将把对该操作的调用移到AddToCart()方法中。如果无论何时添加一个项目,都必须在同一个聚合中发生一些业务不变,那么为什么要把这个责任放在应用程序层呢?这将只允许您的业务逻辑泄漏到域层之外。如果您想要使用基于事件的方法在相同的聚合上内聚地实现这些操作,这是您选择的设计决策,可能更适合,也可能不适合。但是,在添加了项之后,这个处理就不再是应用层的责任了。

但是如果ProcessOrder()方法代表了用户在购物车中添加了一些东西(比如提交订单)之后的下一个步骤,那么您应该问问自己,我与域模型的交互是否太基于 CRUD __?

因此,根据我的经验,DDD通常更适合,或者说更容易适用于基于任务的用户接口。这意味着客户端(例如Web浏览器)通过执行较小的、定义良好的任务与系统进行交互,而不是按照顺序发送更多的数据,而不是转换成在域模型上执行的几个任务(此处是聚合)。

因此,在您的示例中,如果ProcessOrder()的意思是“提交订单”,我将亲自与后端进行两次交互。一个用于向购物车添加一些东西--用例A,另一个用于提交订单--用例B。

对我来说,在这种情况下,从客户的角度来看,这也是比较自然的,因为我希望在不同的步骤中执行这些任务。此外,如果考虑这种方法,则不必处理事件,特别是在相同聚合上操作时。

票数 1
EN

Stack Overflow用户

发布于 2020-07-19 08:36:31

如果您的领域没有太多的上下文,很难判断,但这是您应该从您的产品专家那里得到的答案。

似乎您有一个订单聚合,它公开了一个在购物车上执行操作的公共接口。

  1. 这个聚合真的是OrderAggregate还是ShoppingCartAggregate?
  2. 我假设“过程订单”实际上是指下订单(在我看来,这是这种操作的副作用,我看到付款、库存管理等等)。如果是这样的话,您似乎可以通过以下步骤来改进域的设计:
  • 买方在购物车中添加产品
  • 买方向收银台走去,在购物车中检查产品。
  • 买方付款
  • 买方收到购货收据

(这是对任何商店实际发生的事情的描述,以帮助说明我的想法)

在这一过程中,我们有:

  • 买方是在用例中进化而来的角色。
  • 购物车,这是一个清单的产品,买方有意图购买。但是,由于它们代表着一种意图,放置或移除它们是相当容易的。
  • 签出购物车中的商品实际上是对购物车的最后一个状态进行快照。
  • 由于这一结帐(我假设在您的情况下是过程订单),买方将提示支付和任何其他副作用,可能发生的结帐后。

同样,这是我基于您的描述所做的假设,但我使用它来表明可以从业务流程中实际发生的事情中提取概念,并且领域专家应该帮助您正确地处理这些概念。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62961542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档