六边形架构?小白也能秒懂的「抗造代码秘诀」
😩 开篇暴击:为啥改一行代码,崩了三个服务?
做开发最崩溃的时刻:产品说 "加个小程序端",你改完前端改后端,改完后端改数据库,最后发现订单逻辑崩了;测试说 "换个缓存中间件",你扒着代码改了三天,还把用户数据搞丢了... 这就是传统代码 "牵一发而动全身" 的坑!今天要讲的「六边形架构」,就是专治这种 "代码骨质疏松" 的神药✨ 别被名字吓到,它本质是个 "让业务当老大,技术当小弟" 的设计思路。
🔷 为啥叫 "六边形"?不是因为程序员爱几何!
2005 年有个叫 Alistair Cockburn 的大神发明这架构时,画了张图:核心业务逻辑蹲在正中间,周围伸出六个 "接口触角" 连接外界,看起来像个六边形。这图藏着个关键思想:所有外部系统(网页、数据库、第三方接口)都得 "低头" 通过统一接口找核心,核心却从不搭理它们的 "小脾气" 。
打个比方:核心逻辑是你家客厅🍻,六边形的六条边是家门🚪(端口),门口的鞋架、门禁、快递柜就是 "适配器"🔌。不管是外卖小哥(API)、修水管的(数据库)还是串门的邻居(第三方服务),都得走门、用门口的设备,绝不会让他们直接砸墙进客厅 ------ 这就是 "解耦" 的精髓!

🧠 三分钟看透核心三要素:谁是 "话事人"?
1. 核心域:业务逻辑的 "独立王国" 👑
核心域是整个架构的灵魂,只干一件事:实现业务规则,比如 "订单满 200 减 50""余额不足不能转账"。它有两个超能力:
- 🌰 不碰任何技术细节:不管你用 MySQL 还是 Excel 存数据,不管前端是网页还是 APP,它都漠不关心;
- 🧪 能单独测试:不用连数据库、开服务器,直接给它传数据就能测业务逻辑对不对。
伪代码长这样(看懂逻辑就行,不用管语法):
scss
// 核心业务逻辑:订单处理系统
定义 订单服务:
// 只关心业务规则,不关心数据存在哪
方法 创建订单(用户, 商品列表):
如果 商品库存不足 → 报错"库存不够啦"
计算 总价 = 商品列表求和 - 优惠金额
如果 总价 < 0 → 报错"优惠不能超总价"
调用 订单存储接口.保存订单(订单信息) // 只喊接口,不喊具体数据库
返回 订单编号
2. 端口:核心域的 "沟通暗号" 🚪
核心域不想和外界直接说话,于是搞了套 "暗号本"------ 端口,本质是定义 "怎么对话" 的接口。分两种:
- 输入端口(驱动端口):别人找核心办事的暗号,比如 "创建订单""查询余额";
- 输出端口(被驱动端口):核心找别人办事的暗号,比如 "保存数据""发送短信"。
端口的关键是:用业务语言说话,不说技术术语!比如叫 "保存订单" 而不是 "执行 SQL 插入"。
伪代码示例:
scss
// 输入端口:外部调用核心的接口
定义 订单操作接口:
方法 创建订单(用户, 商品列表) → 订单编号
方法 取消订单(订单编号) → 布尔值
// 输出端口:核心调用外部的接口
定义 订单存储接口:
方法 保存订单(订单信息) → 成功/失败
方法 查订单(订单编号) → 订单信息
3. 适配器:外界的 "翻译官" 🔌
端口是暗号本,但外界不懂暗号啊!比如网页前端只会发 HTTP 请求,数据库只会认 SQL------ 这时候就需要适配器当翻译。适配器也分两种:
- 输入适配器:把外界请求转成核心能懂的暗号,比如把网页的 "下单按钮点击" 转成 "调用订单操作接口。创建订单";
- 输出适配器:把核心的暗号转成外界能懂的指令,比如把 "保存订单" 转成 MySQL 的 INSERT 语句,或 MongoDB 的 save 命令。
最牛的是:换外界系统只需换适配器,核心不动! 比如从 MySQL 换成 PostgreSQL,只改 "数据库适配器",核心的 "保存订单" 逻辑一毛钱不用改。
伪代码演示:
scss
// 输入适配器:网页前端的翻译官
定义 网页订单适配器:
方法 处理网页下单请求(网页参数):
解析 参数 → 用户信息、商品列表
调用 订单操作接口.创建订单(用户信息, 商品列表) // 转成核心能懂的暗号
把 订单编号 转成网页能显示的格式 → 返回给用户
// 输出适配器:MySQL数据库的翻译官
定义 MySQL订单适配器 实现 订单存储接口:
方法 保存订单(订单信息):
把 订单信息 转成 SQL语句 → "INSERT INTO 订单表 VALUES (...)"
执行 SQL → 返回 成功/失败
🛠️ 手把手搭架构:用伪代码建个订单系统
光说不练假把式!咱们用上面的三要素搭个简化版订单系统,全程无具体代码:
第一步:写核心业务逻辑(不管外界)
scss
// 核心域:订单服务(实现输入端口的逻辑)
定义 订单服务 实现 订单操作接口:
// 依赖输出端口的接口,不是具体实现!
接收 订单存储接口 实例 → 存在自己这里
方法 创建订单(用户, 商品列表):
1. 调用 库存服务接口.查库存(商品列表) → 若不足报错
2. 计算 总价 = 商品金额总和 - 用户优惠券
3. 调用 自己存的订单存储接口.保存订单(订单信息)
4. 调用 消息发送接口.发消息(用户ID, "订单创建成功")
5. 返回 订单编号
方法 取消订单(订单编号):
1. 调用 订单存储接口.查订单(订单编号) → 若不存在报错
2. 若 订单已发货 → 报错"不能取消"
3. 调用 订单存储接口.更新订单状态(订单编号, "已取消")
4. 调用 库存服务接口.加库存(商品列表)
5. 返回 成功
第二步:接前端(加输入适配器)
scss
// 输入适配器1:APP适配器
定义 APP订单适配器:
方法 处理APP下单请求(APP参数):
解析 参数 → 用户ID、商品ID列表
调用 订单服务.创建订单(用户ID, 商品ID列表)
返回 JSON格式的订单编号
// 输入适配器2:小程序适配器
定义 小程序订单适配器:
方法 处理小程序下单请求(小程序参数):
解析 参数 → 用户ID、商品ID列表 // 和APP解析方式不同
调用 订单服务.创建订单(用户ID, 商品ID列表) // 但调用核心的方式一样
返回 小程序能识别的响应格式
第三步:接后端(加输出适配器)
json
// 输出适配器1:Redis缓存适配器
定义 Redis订单适配器 实现 订单存储接口:
方法 保存订单(订单信息):
把 订单信息 转成 Redis的键值对 → "订单:123" → {"用户": "张三", ...}
存入 Redis → 返回 成功
// 输出适配器2:短信通知适配器
定义 短信适配器 实现 消息发送接口:
方法 发消息(用户ID, 内容):
查 用户手机号 → 从用户服务接口拿
调用 短信平台API → 发送内容
返回 发送结果
看到没?不管前端加多少端(APP、小程序、网页),后端换多少存储(Redis、MySQL、MongoDB),核心的订单服务永远稳如老狗🐶!
🎯 这些场景闭眼用:六边形架构的 "舒适区"
不是所有项目都需要这架构,找对场景才能事半功倍:
1. 多端适配的系统 📱💻
比如电商系统要支持网页、APP、小程序、第三方 API------ 输入适配器多开几个就行,核心逻辑一次写完。就像餐厅开了堂食、外卖、团餐窗口,厨房还是同一个🍳。
2. 频繁换外部依赖的项目 🔄
比如老板今天说 "用 MySQL 存数据",明天说 "换 MongoDB",后天说 "加个 Redis 缓存"------ 只需换输出适配器,不用改核心。搜索到的阿里案例里,迁移数据库时六边形架构的成本只有传统架构的 1/10!
3. 复杂业务系统 🧩
比如银行的交易系统、医院的挂号系统,业务规则一大堆(满减、折扣、权限控制)。核心域单独维护业务逻辑,测试时不用连数据库,直接 Mock 一个适配器就能测,效率翻倍🚀。
❌ 这些场景别瞎用:杀鸡不用牛刀
- 小工具:比如写个批量重命名文件的脚本,业务逻辑就一行,用这架构纯属给自己找罪受;
- 一次性项目:比如临时做个活动页面,用完就扔,简单的线性代码更快;
- 技术验证原型:重点在试技术,不是稳架构,先跑通再说。
🆚 传统架构 VS 六边形架构:差在哪?
用个通俗比喻:
- 传统分层架构像串糖葫芦🍡:UI 层依赖服务层,服务层依赖 DAO 层,DAO 层依赖数据库 ------ 改数据库,从 DAO 到 UI 全得动;
- 六边形架构像积木城堡🏰:核心是地基,端口是接口,适配器是积木块 ------ 想换窗户(数据库)、门(前端),直接拆旧积木换新品,地基不动。
看个真实对比:电商系统从 MySQL 迁移到 PostgreSQL
| 对比项 | 传统架构 | 六边形架构 |
|---|---|---|
| 核心逻辑修改 | 要改(DAO 层、服务层都碰) | 不改(核心域稳如泰山) |
| 测试范围 | 全系统重测 | 只测新适配器 |
| 迁移时间 | 3 天 | 2 小时 |
| 风险 | 可能改崩业务逻辑 | 几乎零风险 |
代码对比
🍡 传统三层流式架构示例
scss
// Controller 层 (UI 层)
@RestController
public class OrderController {
private final OrderService orderService; // 直接依赖 Service
@PostMapping("/orders")
public String createOrder(@RequestBody OrderRequest request) {
return orderService.createOrder(request.getUser(), request.getItems());
}
}
// Service 层 (业务逻辑 + 技术耦合)
@Service
public class OrderService {
private final OrderDao orderDao; // 直接依赖 DAO
public String createOrder(User user, List<Item> items) {
double total = items.stream().mapToDouble(Item::getPrice).sum();
Order order = new Order(user, items, total);
// 直接调用 DAO 层,耦合数据库
orderDao.insert(order);
return order.getId();
}
}
// DAO 层 (数据库操作)
@Repository
public class OrderDao {
private final JdbcTemplate jdbc;
public void insert(Order order) {
jdbc.update("INSERT INTO orders (id, user, total) VALUES (?, ?, ?)",
order.getId(), order.getUser().getId(), order.getTotal());
}
}
👉 特点:Service 层直接依赖 DAO,DAO 直接依赖数据库。换数据库时,Service 和 DAO 都可能要改。
🏰 六边形架构示例
java
// 输入端口 (业务接口)
public interface OrderUseCase {
String createOrder(User user, List<Item> items);
}
// 输出端口 (抽象接口)
public interface OrderRepository {
void save(Order order);
}
// 核心域 (业务逻辑,只依赖端口)
public class OrderService implements OrderUseCase {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public String createOrder(User user, List<Item> items) {
double total = items.stream().mapToDouble(Item::getPrice).sum();
Order order = new Order(user, items, total);
// 调用抽象接口,不关心具体数据库
orderRepository.save(order);
return order.getId();
}
}
// 输入适配器 (API 层)
@RestController
public class OrderController {
private final OrderUseCase orderService;
@PostMapping("/orders")
public String createOrder(@RequestBody OrderRequest request) {
return orderService.createOrder(request.getUser(), request.getItems());
}
}
// 输出适配器 (数据库实现)
@Repository
public class MySqlOrderRepository implements OrderRepository {
private final JdbcTemplate jdbc;
@Override
public void save(Order order) {
jdbc.update("INSERT INTO orders (id, user, total) VALUES (?, ?, ?)",
order.getId(), order.getUser().getId(), order.getTotal());
}
}
👉 特点:核心域只依赖抽象接口 OrderRepository,具体数据库实现由适配器提供。换数据库时,只需写一个新的适配器(比如 MongoOrderRepository),核心域完全不用改。
📝 最后总结:别被名字吓到!
六边形架构的核心不是 "六边形" 这个形状,而是 "业务优先,技术靠边" 的设计思想 ------ 让最有价值的业务逻辑摆脱技术的束缚,想怎么折腾技术细节就怎么折腾,核心永远安全。
对小白来说,不用一开始就完美实现,先记住三个原则:
- 核心只干业务的事,别碰技术;
- 对外只通过端口说话,别直接唠;
- 适配交给适配器,别让核心当翻译。
下次再遇到 "改一行崩全服" 的坑,试试用六边形架构搭个骨架 ------ 相信我,测试小哥会少追杀你好几次😉!