使用 Web 适配器实现依赖倒置
学习如何使用 Web 适配器实现依赖倒置。
简介
如今大多数应用程序都具备某种形式的 Web 界面——要么是可以通过浏览器交互的 #key# UI:用户界面 #key#,要么是其他系统可调用以与我们的应用进行交互的 #key# HTTP:超文本传输协议 #key# #key# API:应用程序编程接口 #key#。
在我们目标架构中,所有与外界的通信都通过适配器进行。接下来我们讨论如何实现一个提供此类 Web 界面的适配器。
下图详细展示了与 Web 适配器相关的架构元素——适配器本身,以及它与应用核心交互所使用的端口。
带端口的 Web 适配器
Web 适配器是一种“驱动型”或“传入型”适配器。它接收来自外部的请求,并将其转换为对应用核心的调用,告诉核心需要执行什么操作。控制流从 Web 适配器中的控制器流向应用层中的服务。
应用层提供了特定的端口,供 Web 适配器与其通信。这些服务实现了端口接口,而 Web 适配器则通过调用这些端口来与核心交互。
如果我们进一步观察,会发现这正是依赖倒置原则(Dependency Inversion Principle)的实际体现。由于控制流是从左向右的,我们也可以让 Web 适配器直接调用用例(use cases),如下图所示。
直接调用方式
那么,为什么要在适配器和用例之间增加一层间接层呢?原因在于,端口明确定义了外部世界可以与应用核心交互的位置。有了端口,我们就能清楚地知道哪些地方涉及外部通信,这对于维护遗留代码的工程师来说是非常有价值的信息。
尽管如此,在“有意识地走捷径”这一章节中,我们会讨论一种常见的简化做法:省略传入端口,直接调用应用服务。
我们仍需回答一个对高度交互式应用而言非常关键的问题。设想一个通过 WebSocket 向用户浏览器发送实时数据的应用程序。此时,应用核心如何将实时数据发送给 Web 适配器,再由后者转发至用户的浏览器?

对于这种场景,我们必须引入一个端口。该端口应由 Web 适配器实现,并由应用核心调用,如下图所示。
WebSocket 场景
从技术上讲,这是一个传出端口,这意味着 Web 适配器同时扮演了传入和传出适配器的角色。但同一个适配器兼具两种角色并无矛盾之处。
在本章后续内容中,我们将默认 Web 适配器仅为传入型适配器,因为这是最常见的情况。