端口与适配器架构

hexagonal architecture

端口与适配器架构又被称为六边形架构,是一种约定代码设计的架构。它解决的是如何设计代码的问题,主要的关注点在于业务与技术的解耦。

第一次看到这个名字的时候,就有很多问题冒了出来:

  • 它解决什么问题?

  • 什么是端口?什么是适配器?

  • 按照这个架构写出来的代码应该是什么样子?

  • 它为什么又被称作六边形架构?有什么特殊含义?

带着这些问题,搜索了一些资料,算是有了下面的这些理解。

为什么又被称作六边形架构

其实它被称作六边形架构,仅仅是因为它的作者 Dr. Alistair Cockburn 画成这样的而已,没有什么深意。这个架构和“六”这个数字以及“六边形”这个图形都没有任何关联。

那么,这个“六边形”又代表什么呢?

这个“六边形”就是我们所说的“应用”,六边形内的东西,是与技术无关的业务代码。而这些业务代码如何设计,它并没有约定。你可以在内部使用 DDD 战术,也可以使用 “意大利面条式”的代码设计。

一些概念

Actor

Actor 是指那些与应用交互的组件,包括浏览器、命令行甚至其他的应用。所有这些东西都是在我们的“六边形”之外的。

Actor 也有分类,依据是与应用交互的方式:

Drivers

又被称作 Primary Actors。这些 Actor 的特点是它们会调用应用,以完成业务目的。

在画六边形时,Driver 会被画到六边形的左边和上面。

Driven Actors

又被称作 Secondary Actors。这些 Actor 被应用调用,它们提供技术方面的功能以帮助应用完成业务逻辑。

在画六边形时,Driven Actor 会被画到六边形的右边和下边。

Ports

端口处在“六边形”的边缘,用于应用和 Actors 的交互。

根据交互的 Actor 的不同,可以将端口分类为 Driver PortDriven Port ,或者按照《微服务架构设计模式》的说法称作 入站端口出站端口

它们被这样分类是因为:

  • 入站端口提供了访问应用的 API

  • 出站端口被应用调用,提供 SPIDriven Actor 实现

端口描述了应用的业务功能,关注点仍然在业务上。

Driver Port 来说,可以提供一个 createOrder 端口提供下单的功能。

Driven Port 来说,可以提供一个 sendNotification 端口来要求一个发送通知的功能。

Actor 并不是直接和端口交互,而是通过 Adapter 来进行的。

Adapters

适配器处在“六边形”之外,所有的 Actor 都是通过适配器来和 Port 交互,以达到和应用交互的效果。

适配器可以根据适配的端口的不同,分为 Driver AdapterDriven Adapter (或 入站适配器出站适配器 )。

适配器就是从“六边形”中解耦出来的“技术”。

Driver Adapter 来说,可以实现 REST适配器 来提供 REST 风格的接口来调用端口使用应用;也可以实现 CLI适配器 来提供 CLI 接口来调用端口使用应用。

Driven Adapter 来说,可以实现一个 MySQL适配器 以使用 MySQL 持久化数据;也可以实现一个 MongoDB适配器 以使用 MongoDB 持久化数据;也可以实现一个 邮件通知适配器 来实现以邮件形式发送通知的功能。

小结

以上就是端口与适配器架构的核心的概念。

我们可以看到,它的关注点仅仅在于如何将技术代码与业务代码分离开。所以它定义了 ActorsPortsAdapters 这三个概念。而“六边形”并不是一个又特殊含义的东西,只有画出应用的边界和区别 DriverDriven Actor 的作用。

这些概念中,只有 Ports 是属于应用的,其他两个概念都是在应用之外。 - 所有的业务代码,都被包含在了应用之中,而没有被泄漏到应用之外 - 所有需要与第三方交互的技术代码都被放到了 Adapters 里,也就是应用之外,没有侵入到业务代码中

解决的问题

与其他应用交互的代码的设计。

没解决的问题

业务代码怎么写。这需要使用其他的模式来解决,比如 DDD 的战术模式。

如何实现

端口与适配器架构模式要求将应用与适配器分离开,这意味着实现这个模式的时候,需要对应用代码和技术代码做一些技术隔离。 对于 Java 而言,无论是使用 Maven 还是 Gradle 都能比较容易的分离 subproject。其他语言也可以使用类似的技术来实现。虽然不是特别麻烦,但总归是增加了系统的复杂度。

Java 的例子可以参考 这里

总结

总的来说,端口与适配器模式并不复杂,搞清楚三个关键概念和“六边形”没有意义这个点,就算立即到这个架构模式了。