端口和适配器/六边形体系结构 - 术语和实现的说明

los*_*ost 28 architecture hexagonal-architecture

在阅读了有关Ports和Adapters架构的不同来源(包括Alistair Cockburn的原始文章)后,我仍然不确定术语"端口"和"适配器"的确切含义 - 特别是在将这些概念映射到实现工件时.

几个来源(例如这篇文章)暗示这种体系结构模式中的端口是外部的工件,其次是中间层中的适配器,它们在端口和处于核心的应用程序之间进行转换.

但是,在Cockburn的原始文章中,端口出现在适配器层的外部和内部,具体取决于通信方向:

  • 入站通信:" 当事件从外部世界到达端口时,特定于技术的适配器会将其转换为可用的过程调用或消息,并将其传递给应用程序. "
  • 出站通信:" 当应用程序发送内容时,它会通过端口将其发送到适配器,从而创建接收技术所需的适当信号(人工或自动). "

实际上对我来说,"全部外部"方法和"内部和外部"方法都没有意义 - 我会将端口看作始终放在应用程序旁边的工件,而不管通信方向如何.Imo这也与端口适配器的比喻一致:E.g.有一个带有串行端口的设备,要连接另一台没有串口的设备,我需要一个适配器,从我的设备的角度来调整入站和出站通信.

来到这个体系结构的实现,我会看到端口的定义,而不是作为我的应用程序的一部分,我会看到不同的适配器是我的应用程序的"外部".E. g.单个端口的实现可以包括facade(由适配器调用以进行入站通信)和interface(由适配器实现用于出站通信).

术语端口适配器的正确含义是什么?如何将这些概念映射到实现工件?

更新:

发现这篇文章类似于我的理解.如果存在某种共同协议,问题仍然存在.

Vla*_*ler 22

inf3rno给出了一个很好的答案,澄清了原始问题,但强调端口和适配器的一些其他用途可能是有用的.

根据我的理解,端口是您的界面的表达.

港口:

  • 定义核心功能的暴露(对于"传入"端口)
  • 定义核心对外界的看法(对于"外向"端口)

适配器:

  • 位于组件外(六角形)
  • 用于确保端口和目标之间的传输以满足与端口接口的合同的方式发生
  • 是你替换(使用依赖注入)来测试六边形

端口应接受适配器并确保适配器实现接口.然后它应该只在适配器上调用适当的方法/函数.

该端口应包含在通信测试中.在这种情况下,"模拟"的是两个相邻六边形(或六边形和服务)的核心,并测试端口/适配器/适配器/端口组件.

有关更多信息,您可以查看James Gardner和我在2014年7月伦敦Skillsmatter Microservices 聚会上所提供的六角形微服务的讨论.

  • 对您的小建议:当您添加指向您创建的资源的链接时,您可能希望将您的单词选择从"请查看我的谈话......"更改为"更多信息,您可以查看我在......"在这种情况下,你所链接的谈话似乎是问题的主题,所以应该没问题.如果您不小心,可能会被视为垃圾邮件或自我推销. (3认同)

inf*_*rno 17

我认为这是非常简单的概念.你有应用程序核心,它不依赖于它之外的任何东西.例如,它不依赖于HTTP框架,数据库驱动程序,邮件框架等等......根据您的问题域,此核心具有非常特定的接口,因此只有在您的问题域发生更改时,应用程序核心的代码才会更改.

例如,您有博客文章,并且您想要为它们添加类别.因此,类别应该流经整个系统,从HTTP通信到数据库通过写入,反之亦然.

现在,如果你想用MongoDB替换MySQL数据库,那该怎么办呢?它不应该影响核心,因为应用程序仍然完全相同:它存储您的博客帖子和ofc.他们的类别并按需返回.所以你需要的只是这种情况下的MondogDB适配器,你可以使用它而不是你的MySQL适配器.

如果您想要一个REST API,而不仅仅是一个简单的HTML页面,该怎么办?它仍然不会影响您的应用程序核心,因此您需要的是另一个用于REST通信的适配器.

因此,在我看来,您的适配器应该具有在应用程序核心中定义的特定接口,并且端口应该使用这些适配器与应用程序核心通信.所以在我看来,端口不必作为类,只是适配器及其接口存在.这个概念很有意义,因为您的应用程序核心不会紧密耦合到您想要使用的端口,而只是紧跟您定义的适配器接口.(顺便提一下,有许多相似的架构.就像干净的架构,洋葱架构,它使用相同的概念和不同的词汇.)

  • 我很感激你的详细答案,但最后还是没有详细说明我原来的问题.仍希望得到更多澄清. (2认同)

Gra*_*Lea 8

我工作的人在这个架构上做了很好的内部演示.最后,在提问期间,另一位同事问道:

这不仅仅是一个具有不同名称和不同名称的分层架构吗?

而且,说实话,这在很大程度上是正确的.对于许多应用程序,六边形体系结构的结构与分层体系结构相同,只有一些具体细节:

  • 定义每个层(端口)之间的接口而不是将impl调用impl有更多的纪律.
  • 关注"核心"(业务逻辑)是最重要的层,所有其他层(适配器)被视为有些屈服.
  • 从核心角度定义接口的重点是防止适配器的语言泄漏到核心.例如,如果你将持久性(例如Hibernate)放入适配器中,那么你的核心不应该有任何@Entity类.

你可以看到,即使做了所有这些事情,它仍然只是一个分层的架构,只是层之间的界限非常严格,而且关注中心层.

因此,要专门回答这个问题,您可以通过识别端口是进出核心的接口来理解端口和适配器,而适配器只是不是核心的实现层.