首页 > 解决方案 > 领域驱动设计 (DDD):领域事件处理程序——将它们放置在哪里?

问题描述

我对在基于六边形架构的应用程序中处理域事件的位置感到困惑。我说的是有界上下文内部域事件,而不是上下文集成/应用程序/公共事件。

背景

据我了解,应用程序逻辑(即用例逻辑、工作流逻辑、与基础设施的交互等)是命令处理程序所属的地方,因为它们特定于某个应用程序设计和/或 UI 设计。然后,命令处理程序调用所有域逻辑所在的域层(域服务、聚合、域事件)。领域层应该独立于特定的应用程序工作流和/或 UI 设计。

在许多资源(博客、书籍)中,我发现人们在应用层实现域事件处理程序,类似于命令处理程序。这是因为域事件的处理应该在它自己的事务中完成。由于它可能会影响其他聚合,因此必须首先通过基础架构加载这些聚合。然而,关键点是:领域事件被撕裂并变成一系列对聚合的方法调用。这个重要的翻译只存在于应用层。

问题

我认为关于哪些领域事件会对其他聚合产生什么影响的知识是领域知识本身的一个组成部分。如果我要删除除我的领域层之外的所有内容,那么这些知识不应该保留在某个地方吗?在我看来,我们应该将领域事件处理程序直接放在领域层本身:

当然,为了加载受影响的聚合,我们仍然需要在应用层有一个对应的处理程序。这个处理程序只启动一个新事务,加载感兴趣的聚合并调用到域层。

由于我从未在任何地方看到过这个,我想知道我是否对 DDD、域事件或应用层和域层之间的区别有什么问题。

编辑:示例

让我们从这个常用的方法开始:

// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
    var restaurant = this.restaurantRepository.getByOrderKind(event.kind);
    restaurant.prepareMeal(); // Translate the event into a (very different) command - I consider this important business knowledge that now is only in the application layer.
    this.mailService.notifyStakeholders();
}

而这个呢?

// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
    var restaurant = this.restaurantRepository.getByOrderKind(event.kind);
    this.restaurantDomainService.HandleDomainEvent(event, restaurant);
    this.mailService.notifyStakeholders();
}

// in domain layer handler (called by above)
public void HandleDomainEvent(OrderCreatedDomainEvent event, Restaurant restaurant) {
    restaurant.prepareMeal(); // Now this translation knowledge (call it policy) is preserved in only the domain layer.
}

标签: domain-driven-designbusiness-logicdomain-eventshexagonal-architecture

解决方案


大多数偶数处理程序类的问题在于,它们通常与特定的消息传递技术相关联,因此通常放置在基础设施层中。

但是,没有什么能阻止您编写与技术无关的处理程序并使用分派给它们的技术感知适配器。

例如,在我构建的一个应用程序中,我有一个Action Required Policy的概念。每当满足/不满足策略规则时,该策略就会将给定工作项的分配/取消分配到一个特殊的工作负载桶。在许多情况下必须重新评估该策略,例如何时将文档附加到工作项、分配工作项、授予外部状态标志等。

我最终ActionRequiredPolicy在域中创建了一个类,该类具有事件处理方法,例如void when(CaseAssigned event),我在基础设施层中有一个偶数处理程序,它只是通知策略。

我认为人们将它们放在infrastructureorapplication层中的另一个原因是,策略通常通过触发新命令来对事件做出反应。有时这种方法感觉很自然,但有时您想明确表示必须为响应事件而发生动作,否则无法发生:将事件转换为命令会使其不那么明确。

这是我提出的与此相关的一个较旧的问题。


推荐阅读