六边形架构与端口适配器
用途:判断“外部依赖该怎么接进来”、如何做到换 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 | 提供具体目录结构与组件(含扩展点),可视为工程模板 |
| 事件驱动 | 输出端口用事件发布替代直接调用,适配器负责投递 |
落地注意
「落地注意」小节链接- 不要为每个小工具都建端口,端口服务于可替换性与可测试性,只在真正需要隔离时引入。
- 适配器内不写业务规则,规则回到核心;否则换适配器等于换业务。
- 组合根(依赖注入容器)是唯一知道全部实现的地方,放在启动模块。
- 用架构测试固化“核心不依赖适配器包”。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
| 端口=Repository 接口堆砌 | 端口面向用例意图,不是 CRUD 抽象 |
| 核心层引入框架注解 | 至少隔离持久化与协议细节 |
| 适配器里做业务判断 | 判断进核心,适配器只做转换与调用 |
| 抽象层数过多导致读代码要跳五次 | 小模块允许直接实现,按需抽象 |
延伸阅读
「延伸阅读」小节链接- Alistair Cockburn《Hexagonal Architecture》原文与配图
- Robert C. Martin《Clean Architecture》第 22 章(边界与依赖)
- Vaughn Vernon《实现领域驱动设计》第 11 章(六边形与基础设施关注点)