DDD的端口和适配器与洋葱架构,应该将哪些内容放在哪里?

7

我正在努力理解一些概念,但却无法理解:

Ports and Adapters架构中的用例是什么?

用例实现是什么样子的?

用例关注点是什么?

它在基础设施或域中的位置在哪里?它说应该放在应用程序中,那么应用程序核心和应用程序服务是不同的吗?

在左侧,适配器依赖端口并注入端口的具体实现,其中包含用例。在这一侧,端口及其具体实现(用例)都属于应用程序;

https://herbertograca.com/2017/09/14/ports-adapters-architecture/#what-is-a-port

这段引用让我困惑了...因为据我所知,主要适配器可以是任何请求您的业务逻辑的东西(它对您提供的内容感兴趣),例如WebAPI、MVC、Testing、ConsoleApp。

在左侧,适配器依赖于端口,并注入端口的具体实现,其中包含用例。

所以我认为它是指将你的业务逻辑注入到WebApiController构造函数中。

在这一侧,端口及其具体实现(用例)都属于应用程序;

那么是什么?谁是这个应用程序?是WebApi吗?还是域?另外,据我所知,用例是我的业务逻辑的实现,例如设计会是这样的吗?

Client :
WebApiController(IMyBusinessServicePort service)

Infrastructure :
ImplementingPrimaryAdapter : IMyBusinessServicePort { }
ImplementingSecondaryAdapter : ILoggingPort { }

Domain :
ImplementMyBusinessLogicService : IMyBusinessLogicService 

那么WebApiController将使用由ImplementingPrimaryAdapter提供的实现,而不是我的领域中的某些东西吗?我不明白。请解释一下。
3个回答

4

六边形架构并不涉及六边形的内部结构。

用例适用情况如下:

驱动程序端口是应用程序(六边形)的用例边界。用例接口将是驱动程序端口。用例的实现将是六边形内部的一个类。

Alistair所称的应用程序不是DDD应用程序层,而是业务逻辑作为整体的六边形,与技术解耦。如果要与DDD层进行比较,则必须将六边形分为两个层:应用程序和领域。ddd基础设施层将是六边形外部的适配器。

但是,六边形架构并不涉及DDD,它们是不同的东西。如何将DDD与六边形架构相结合取决于您。

我写了一篇关于六边形架构的文章,如果您想修正概念:

https://jmgarridopaz.github.io/content/hexagonalarchitecture.html

希望能有所帮助。


请问,如果驱动端口代表第三方包、库、框架的抽象,而驱动适配器只是这些端口的实现。那么驱动端口是如何表示的?谁会实现它?这是 MediatR 的应用场景吗?只是为了尽快将音乐会传递给应用程序?因此,MediatR 是实际的驱动适配器,而 WebApi 是驱动端口,对吗? - user9124444
3
驱动端口由六边形内部实现,当需要来自外部世界的东西时,实现会调用驱动器端口。我在我的文章中有解释。 - choquero70

1

根据您使用的基于调用栈的编程或例如Actor模型,实现方式会有所不同。

接下来,我将讨论与DDD和CQRS中“C”部分最接近的案例:更改系统状态。从六边形的角度来看,“Q”部分比较简单:其复杂性主要在适配器方面。

对于我来说,我将词汇放在六边形的核心位置。它映射到DDD普遍语言模型,并由包含这些数据结构上业务不变量验证的不可变数据结构组成。

接下来是决策点。当您做出决策时,根据单一责任原则,您应该只做这件事。不进行外部调用、IO等操作。因此,您需要一些信息来做出决策。当这些信息被收集后,可以将其包装在一个命令对象中。您将其传递给决策者,它大致映射到DDD聚合。然后,它要么批准命令并生成事件或更改集(无论您是否进行事件溯源),要么拒绝。没有任何外部调用。即它不使用任何六边形的端口。

在六边形内部剩下的是收集外部数据、调用决策制定者和处理结果的逻辑。这个逻辑可以建模为简单的有限状态机并进行单元测试。这就是我在六边形中所称的用例。因为这是数据在端口之间流动和决策制定者协调的地方。所以,用例使用端口。
在六边形的主要端口接收到业务请求后,会创建一个用例实例。有一个用例FSM和执行器,实际上调用次要端口,接收它们的响应并推进用例FSM。
用例的处理流程可能包括以下步骤:
  • 验证接收到的业务请求
  • 如果无效 - 用错误格式化业务响应
  • 如果有效 - 准备向次要端口发送请求
  • 发送准备好的请求
  • 接收次要端口的响应
  • 在失败或超时的情况下 - 用错误格式化业务响应
  • 如果成功收集数据,为决策者准备命令
  • 调用决策者并获取事件/变更/拒绝
  • 如果被拒绝 - 用错误格式化业务请求
  • 如果被接受 - 为次要端口准备另一组请求以执行决策:持久化到数据库,发送到消息队列,发射火箭等
  • 等待次要端口执行请求
  • 如果失败 - 用错误格式化业务响应
  • 如果正常 - 用成功格式化业务响应

因此,用例肯定属于领域,因为它不依赖于适配器的实现,而是依赖于它们的接口。它形成了领域的应用程序层。

将用例放在单独的代码片段中很有用,因为这样该代码就具有单一的更改原因 - 如果用例更改了。它不同于决策逻辑或领域值验证逻辑。


1

领域 :

  1. 端口(连接领域与基础设施)
  2. 应用程序服务
  3. 领域服务
  4. 领域工厂
  5. 领域实体

基本上,您不会将任何基础设施问题泄漏到您的领域中,而是使用抽象。

基础架构层,任何可能会发生变化的内容,如ORM、缓存、日志等等...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接