Java 23 种设计模式:从踩坑到精通 | 番外:中介者模式 —— 物流服务协调实战
摘要:中介者模式用一个中介对象来封装一系列对象的交互,使各对象不需要显式地相互引用,从而使其耦合松散,将网状的多对多依赖关系转变为以中介者为中心的星型结构。本文结合智能物流调度中心的场景,完整展示如何用中介者协调订单、库存、配送三大服务的交互,并与外观模式深度对比,帮你掌握“化网为星”的设计精髓。
🗺️本文阅读地图(3 分钟速览)
- 为什么订单、库存、配送服务不能直接互相调用?
- 中介者核心角色:抽象中介者、具体中介者、抽象同事、具体同事
- 手写物流调度中心:订单创建 → 库存扣减 → 配送发货,全程由中介者协调
- 中介者 vs 外观:双向协调 vs 单向简化
- 面试必问:“中介者模式和外观模式有什么区别?
DispatcherServlet用了哪个?”
📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 | 正篇:Mediator 中介者模式 —— 对象关系太乱?请一位“中间人” |当前:番外 · 中介者模式 × 物流服务协调
🔗 返回系列总目录
1. 物流服务交互的痛点
在智能物流系统中,订单服务、库存服务、配送服务之间存在紧密的协作关系:订单创建后需要通知库存扣减,库存确认后需要通知配送发货,配送完成后需要通知订单更新状态。如果让这三个服务直接互相调用:
// 订单服务直接依赖库存服务和配送服务classOrderService{privateInventoryServiceinventoryService;privateDeliveryServicedeliveryService;voidcreateOrder(){inventoryService.deductStock();// 直接调用库存deliveryService.arrangeDelivery();// 直接调用配送}}这种写法会让服务之间形成网状依赖——每新增一个服务(如支付服务、通知服务),所有相关服务都要修改。更糟糕的是,服务之间的调用顺序和交互规则散落在各服务内部,难以统一管理和动态调整。
中介者模式的解决思路:引入一个调度中心(中介者),让所有服务只与调度中心通信,不再直接互相调用。订单创建后通知调度中心,调度中心决定接下来调用库存服务,库存确认后再由调度中心调用配送服务——所有交互逻辑集中在调度中心内,各服务只需关注自己的业务。
1.1 你的场景该不该用中介者?
| 判断标准 | 是 → 用中介者 | 否 → 用其他方式 |
|---|---|---|
| 多个对象之间形成复杂的网状交互,耦合严重 | ✅ | ❌ |
| 交互逻辑频繁变化,需要集中管理和动态调整 | ✅ | ❌ |
| 希望各组件独立开发、独立测试 | ✅ | ❌ |
| 只有简单的一对一调用关系,无网状依赖 | ❌ | 直接调用即可 |
2. 中介者模式 UML(物流调度中心场景)
3. 完整源码实现
3.1 抽象中介者接口 (Mediator)
/** * 抽象中介者:定义同事类通知中介者的统一接口 */publicinterfaceMediator{voidnotify(Colleaguesender,Stringevent);}💬白话:中介者只有一个核心方法——接收来自某个同事的消息,然后决定下一步通知谁。
3.2 抽象同事类 (Colleague)
/** * 抽象同事类:所有具体同事的基类 */publicabstractclassColleague{protectedMediatormediator;protectedStringname;publicColleague(Mediatormediator,Stringname){this.mediator=mediator;this.name=name;}publicabstractvoidsend(Stringevent);publicabstractvoidreceive(Stringevent);}💬白话:每个同事都持有中介者的引用,发消息走中介者,收消息也从中介者来。同事之间互不相识。
3.3 具体中介者:物流调度中心 (ConcreteMediator)
/** * 具体中介者:物流调度中心,协调各服务之间的交互 */publicclassConcreteMediatorimplementsMediator{privateConcreteColleagueAorderService;privateConcreteColleagueBinventoryService;privateConcreteColleagueCdeliveryService;@Overridepublicvoidnotify(Colleaguesender,Stringevent){System.out.println("\n📡 [调度中心] 收到来自 ["+sender.name+"] 的消息:"+event);if(sender==orderService){handleOrderEvent(event);}elseif(sender==inventoryService){handleInventoryEvent(event);}elseif(sender==deliveryService){handleDeliveryEvent(event);}}privatevoidhandleOrderEvent(Stringevent){if(event.contains("已创建")){System.out.println(" → 调度中心:通知库存服务扣减库存");inventoryService.receive("订单已创建,请扣减库存");}}privatevoidhandleInventoryEvent(Stringevent){if(event.contains("库存充足")){System.out.println(" → 调度中心:通知配送服务安排发货");deliveryService.receive("库存已确认,请安排配送");}elseif(event.contains("库存不足")){System.out.println(" → 调度中心:通知订单服务取消订单");orderService.receive("库存不足,订单已取消");}}privatevoidhandleDeliveryEvent(Stringevent){if(event.contains("已发货")){System.out.println(" → 调度中心:通知订单服务更新物流状态");orderService.receive("商品已发货,物流单号:SF123456789");}}publicvoidsetOrderService(ConcreteColleagueAorderService){this.orderService=orderService;}publicvoidsetInventoryService(ConcreteColleagueBinventoryService){this.inventoryService=inventoryService;}publicvoidsetDeliveryService(ConcreteColleagueCdeliveryService){this.deliveryService=deliveryService;}}💬白话:调度中心是“大脑”——它知道所有服务,所有交互规则都写在这里。订单创建后该做什么、库存确认后该做什么,全部集中管控。新增一个服务只需在中介者中增加对应的处理方法。
3.4 具体同事类:订单/库存/配送服务
/** * 具体同事类A:订单服务 */publicclassConcreteColleagueAextendsColleague{publicConcreteColleagueA(Mediatormediator,Stringname){super(mediator,name);}@Overridepublicvoidsend(Stringevent){System.out.println("📦 ["+name+"] 发送消息:"+event);mediator.notify(this,event);}@Overridepublicvoidreceive(Stringevent){System.out.println(" 📥 ["+name+"] 收到消息:"+event);}}/** * 具体同事类B:库存服务 */publicclassConcreteColleagueBextendsColleague{publicConcreteColleagueB(Mediatormediator,Stringname){super(mediator,name);}@Overridepublicvoidsend(Stringevent){System.out.println("📦 ["+name+"] 发送消息:"+event);mediator.notify(this,event);}@Overridepublicvoidreceive(Stringevent){System.out.println(" 📥 ["+name+"] 收到消息:"+event);if(event.contains("扣减库存")){booleanhasStock=true;// 模拟库存充足if(hasStock){send("库存充足,扣减完成");}else{send("库存不足,无法扣减");}}}}/** * 具体同事类C:配送服务 */publicclassConcreteColleagueCextendsColleague{publicConcreteColleagueC(Mediatormediator,Stringname){super(mediator,name);}@Overridepublicvoidsend(Stringevent){System.out.println("📦 ["+name+"] 发送消息:"+event);mediator.notify(this,event);}@Overridepublicvoidreceive(Stringevent){System.out.println(" 📥 ["+name+"] 收到消息:"+event);if(event.contains("安排配送")){send("已发货,物流单号:SF123456789");}}}💬白话:每个服务只做两件事——
send发消息给中介者,receive收消息并执行自己的业务逻辑。它们完全不知道其他服务的存在。
3.5 客户端测试
publicclassClient{publicstaticvoidmain(String[]args){ConcreteMediatordispatcher=newConcreteMediator();ConcreteColleagueAorderService=newConcreteColleagueA(dispatcher,"订单服务");ConcreteColleagueBinventoryService=newConcreteColleagueB(dispatcher,"库存服务");ConcreteColleagueCdeliveryService=newConcreteColleagueC(dispatcher,"配送服务");dispatcher.setOrderService(orderService);dispatcher.setInventoryService(inventoryService);dispatcher.setDeliveryService(deliveryService);System.out.println("=== 场景:用户下单,触发完整物流流程 ===\n");orderService.send("订单已创建,订单号:20240723001");System.out.println("\n=== 流程结束 ===");}}4. 运行结果
=== 场景:用户下单,触发完整物流流程 === 📦 [订单服务] 发送消息:订单已创建,订单号:20240723001 📡 [调度中心] 收到来自 [订单服务] 的消息:订单已创建,订单号:20240723001 → 调度中心:通知库存服务扣减库存 📥 [库存服务] 收到消息:订单已创建,请扣减库存 📦 [库存服务] 发送消息:库存充足,扣减完成 📡 [调度中心] 收到来自 [库存服务] 的消息:库存充足,扣减完成 → 调度中心:通知配送服务安排发货 📥 [配送服务] 收到消息:库存已确认,请安排配送 📦 [配送服务] 发送消息:已发货,物流单号:SF123456789 📡 [调度中心] 收到来自 [配送服务] 的消息:已发货,物流单号:SF123456789 → 调度中心:通知订单服务更新物流状态 📥 [订单服务] 收到消息:商品已发货,物流单号:SF123456789 === 流程结束 ===5. 核心角色回顾
| 角色 | 职责 | 对应代码 |
|---|---|---|
| Mediator | 定义同事与中介者的通信接口 | Mediator |
| ConcreteMediator | 协调各同事的交互,集中管控规则 | ConcreteMediator |
| Colleague | 持有中介者引用,通过中介者通信 | Colleague |
| ConcreteColleague | 实现自身业务,发消息给中介者 | ConcreteColleagueA/B/C |
6. 中介者模式 vs 外观模式
| 对比项 | 中介者模式 | 外观模式 |
|---|---|---|
| 意图 | 协调多个对象之间的双向交互 | 为子系统提供单向统一入口 |
| 通信方向 | 同事 ↔ 中介者 ↔ 同事(双向) | 客户端 → 外观 → 子系统(单向) |
| 子系统感知 | 同事类知道中介者的存在 | 子系统不知道外观的存在 |
| 典型应用 | 物流调度中心、聊天室、DispatcherServlet | SLF4J、JdbcTemplate、微服务网关 |
💡一句话记忆:中介者是“中控台”——双向协调,每个服务都知道中介者;外观是“一键启动”——单向简化,子系统不知道外观的存在。
7. 中介者模式的优缺点
| 优点 | 缺点 |
|---|---|
| 同事类之间零依赖,从网状变星型 | 中介者可能膨胀为“上帝类” |
| 交互逻辑集中管控,修改方便 | 所有通信经过中介者,可能成为性能瓶颈 |
| 各组件可独立开发、独立测试 | 设计复杂度增加 |
8. 六大设计原则体现
| 原则 | 体现 |
|---|---|
| 单一职责 | 同事负责自身业务,中介者负责协调 |
| 开闭原则 | 新增同事类通常无需修改中介者(新增交互规则时需修改) |
| 里氏替换 | 所有同事可替换抽象Colleague |
| 依赖倒置 | 同事依赖抽象Mediator接口 |
| 接口隔离 | Mediator只有notify()一个方法 |
| 迪米特法则 | 同事只与中介者通信,不知其他同事存在 |
附 中介者模式 UML源码(物流调度中心场景)
@startuml title Java 23 种设计模式:从踩坑到精通 footer 折哥 | 智能物流与Java实战 ' 1. 全局样式配置 skinparam backgroundColor #FEFEFE skinparam shadowing false skinparam classBorderColor #333333 skinparam classFontColor #1A1A1A skinparam classFontSize 14 skinparam noteFontSize 12 skinparam noteFontColor #555555 skinparam arrowColor #555555 skinparam classBackgroundColor #F9F9F9 skinparam interface { BackgroundColor #E8F5E9 BorderColor #2E7D32 } ' 2. 抽象中介者 interface Mediator { + notify(sender, event) } note right of Mediator <b>抽象中介者</b> -- 定义同事类通知中介者的统一接口 封装对象间的交互逻辑 end note ' 3. 具体中介者 class ConcreteMediator implements Mediator { - colleagueA : ConcreteColleagueA - colleagueB : ConcreteColleagueB + notify(sender, event) + setColleagueA(Colleague) + setColleagueB(Colleague) } note right of ConcreteMediator <b>具体中介者</b> -- 协调各同事类之间的交互 知道所有同事类,但同事类不知道彼此 end note ' 4. 抽象同事类 abstract class Colleague { - mediator : Mediator + send(event) + receive(event) } note right of Colleague <b>抽象同事类</b> -- 持有中介者引用 通过中介者与其他同事通信 不直接依赖其他同事类 end note ' 5. 具体同事类A class ConcreteColleagueA extends Colleague { + send(event) + receive(event) } note right of ConcreteColleagueA <b>具体同事类A</b> -- 例如:订单服务 只与中介者通信 end note ' 6. 具体同事类B class ConcreteColleagueB extends Colleague { + send(event) + receive(event) } note right of ConcreteColleagueB <b>具体同事类B</b> -- 例如:库存服务 只与中介者通信 end note ' 7. 关系连线 Colleague o-down-> Mediator : 依赖 ConcreteMediator .up.> Mediator : 实现 ConcreteColleagueA -up-|> Colleague : 继承 ConcreteColleagueB -up-|> Colleague : 继承 ConcreteMediator --> ConcreteColleagueA : 协调 ConcreteMediator --> ConcreteColleagueB : 协调 @enduml🧭 《Java 23 种设计模式:从踩坑到精通》快速导航
- 开篇:系列介绍与目录
- 正篇:Mediator 中介者模式 —— 对象关系太乱?请一位“中间人”
- 当前:番外 · 中介者模式 × 物流服务协调(你在这里)
- 创建型模式汇总
- 结构型模式汇总
- 行为型模式汇总
🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》、《电商多平台电子面单对接实战》。技术相通,思路可鉴。