跳转到内容

六边形架构与端口适配器

用途:判断“外部依赖该怎么接进来”、如何做到换 UI/换数据库不动业务时查阅

六边形架构(Ports & Adapters,Alistair Cockburn 提出)把系统画成中心的应用核心,周围通过端口(接口)与外界交互,适配器实现端口:

  • 驱动端口(输入端口):外界调用系统——用例接口(HTTP Controller、消息消费者、定时任务都是它的适配器)。
  • 被驱动端口(输出端口):系统调用外界——仓储接口、外部服务客户端接口、事件发布接口(DB/Redis/MQ/第三方 API 的适配器实现它们)。

核心不 import 任何技术细节,方向始终是适配器 → 核心。

传统三层里“业务层依赖 DAO 层”,导致:换数据库要改业务、测业务要起数据库、UI 变化牵连逻辑。六边形把“业务用例”与“交互方式”彻底解耦,使同一套用例可以被 Web、CLI、批处理、测试桩复用。

端口是用例需要的能力,不是数据库表的操作集合:

反例(技术导向) 正例(意图导向)
UserDAO.selectById AccountRepository.findById
HttpClient.post(url, body) RiskControlGateway.evaluate(order)
MQProducer.send(topic, msg) OrderEventPublisher.publish(event)

判据:端口名字里不应出现技术名词(表、topic、URL、缓存)。

核心逻辑可用内存实现或桩适配器测试,不起任何外部组件;集成测试只覆盖适配器本身。这让“业务规则有测试”变得低成本,是六边形最实际的收益。

风格 与六边形的关系
洋葱 / 整洁架构 同一思想的同心圆表述,强调层间依赖规则
DDD 四层 四层给出角色划分,六边形强调“两侧对称的端口/适配器”
COLA 提供具体目录结构与组件(含扩展点),可视为工程模板
事件驱动 输出端口用事件发布替代直接调用,适配器负责投递
  1. 不要为每个小工具都建端口,端口服务于可替换性与可测试性,只在真正需要隔离时引入。
  2. 适配器内不写业务规则,规则回到核心;否则换适配器等于换业务。
  3. 组合根(依赖注入容器)是唯一知道全部实现的地方,放在启动模块。
  4. 用架构测试固化“核心不依赖适配器包”。
误区 修正
端口=Repository 接口堆砌 端口面向用例意图,不是 CRUD 抽象
核心层引入框架注解 至少隔离持久化与协议细节
适配器里做业务判断 判断进核心,适配器只做转换与调用
抽象层数过多导致读代码要跳五次 小模块允许直接实现,按需抽象
  • Alistair Cockburn《Hexagonal Architecture》原文与配图
  • Robert C. Martin《Clean Architecture》第 22 章(边界与依赖)
  • Vaughn Vernon《实现领域驱动设计》第 11 章(六边形与基础设施关注点)