Java 23 种设计模式:从踩坑到精通 | 中介者模式 —— 对象关系太乱?请一位“中间人”

📅 2026/7/6 17:53:51 👁️ 阅读次数 📝 编程学习
Java 23 种设计模式:从踩坑到精通 | 中介者模式 —— 对象关系太乱?请一位“中间人”

Java 23 种设计模式:从踩坑到精通 | Mediator —— 对象关系太乱?请一位“中间人”

摘要:当多个对象之间形成复杂的网状交互时,直接相互引用会导致“牵一发而动全身”的维护灾难。中介者模式通过引入一个中间协调对象,将所有交互逻辑集中管控,让原本互相引用的对象只与中介者通信,从而将“多对多”转为“一对多”。本文从智能家居设备联动的场景出发,完整讲解中介者模式的原理、UML、代码实现,与外观模式进行深度对比,并结合 Spring MVCDispatcherServlet、消息中间件、微服务注册中心等框架应用,帮你掌握“化网为星”的设计精髓。

🗺️本文阅读地图(3 分钟速览)

  • 为什么设备之间互相引用会爆炸?
  • 中介者模式核心角色拆解
  • 手写智能家居中控(电视、窗帘、灯光联动)
  • 聊天室案例:广播消息一目了然
  • Spring MVCDispatcherServlet/ 消息中间件 / 注册中心如何体现
  • 面试必问:中介者 vs 外观,到底怎么区分?

📖《Java 23 种设计模式:从踩坑到精通》
开篇:系列介绍与目录 | 上一篇:迭代器模式 |当前:中介者模式| 下一篇:备忘录模式
🔗 返回系列总目录


文章目录

  • Java 23 种设计模式:从踩坑到精通 | Mediator —— 对象关系太乱?请一位“中间人”
    • 1. 从一个“设备联动”的交互噩梦说起
      • 1.1 你的场景该不该用中介者?
    • 2. 模式定义与 UML 结构
      • 图文解析(配合上述 UML 图)
    • 3. 代码实现:智能家居中控
      • 3.1 抽象中介者
      • 3.2 抽象同事类
      • 3.3 具体同事类:电视、窗帘、灯光
      • 3.4 具体中介者:智能中控
      • 3.5 客户端
    • 4. 代码实现:聊天室(经典面试场景)
      • 4.1 中介者
      • 4.2 具体中介者
      • 4.3 同事类:用户
      • 4.4 客户端
    • 5. 优缺点一览
    • 6. 中介者模式 vs 外观模式
    • 7. 框架与实践中的应用
      • 7.1 Spring MVC:`DispatcherServlet`
      • 7.2 消息中间件(RabbitMQ、Kafka)
      • 7.3 微服务注册中心(Eureka、Nacos)
    • 8. 面试必问 + 面试官追问连环炮
    • 9. 六大设计原则在中介者模式中的体现
    • 🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

1. 从一个“设备联动”的交互噩梦说起

假设你正在开发一套智能家居系统,有窗帘、灯光、电视、空调等多个设备,它们之间存在复杂的联动规则:

  • 打开电视时,窗帘自动关闭,灯光调暗;
  • 打开空调时,窗户自动关闭;
  • 按下“离家模式”时,所有设备全部关闭;
  • ……

如果不加设计,每个设备对象都要持有其他设备的引用:

classTV{privateCurtaincurtain;privateLightlight;voidon(){curtain.close();light.dim();}}classAirConditioner{privateWindowwindow;voidon(){window.close();}}

这种网状结构的耦合是灾难性的:

  • 新增一个设备(如加湿器),所有相关设备都要修改;
  • 修改一条联动规则,可能要改动多个设备类;
  • 设备之间互相依赖,单元测试几乎无法独立进行。

中介者模式(Mediator Pattern)正是为解决“多对多”对象交互问题而生的:它引入一个中介者对象,封装所有对象之间的交互逻辑,让每个对象只与中介者通信,从而将网状结构变为星型结构。

1.1 你的场景该不该用中介者?

判断标准是 → 用中介者否 → 用其他方式
多个对象之间形成复杂的网状依赖关系
交互逻辑频繁变化,需要集中管理
希望各组件独立开发、独立测试
只有简单的一对一调用关系直接调用即可

2. 模式定义与 UML 结构

中介者模式用一个中介对象来封装一系列对象的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。它属于行为型设计模式

图文解析(配合上述 UML 图)

中介者模式的核心角色:

  • 抽象中介者(Mediator:定义同事对象到中介者的通信接口,通常只有一个notify(sender, event)方法。
  • 具体中介者(ConcreteMediator:实现中介者接口,管理所有同事对象,协调它们之间的交互逻辑。这是整个模式的核心。
  • 抽象同事类(Colleague:持有中介者引用,发送消息时通过中介者转发,自己不与其他同事直接通信。
  • 具体同事类(ConcreteColleagueA/ConcreteColleagueB:实现自身业务逻辑,通过中介者与其他同事交互。

核心机制:同事类从“互相认识”变为“只认识中介者”。发送消息时调用mediator.notify(this, event),由中介者决定通知哪些同事。这就是从“网状结构”到“星型结构”的关键。


3. 代码实现:智能家居中控

3.1 抽象中介者

publicinterfaceMediator{voidnotify(Componentsender,Stringevent);}

💬白话:中介者只需一个方法——谁发了什么事,我来决定告诉谁。

3.2 抽象同事类

publicabstractclassComponent{protectedMediatormediator;publicComponent(Mediatormediator){this.mediator=mediator;}publicvoidsend(Stringevent){mediator.notify(this,event);}publicabstractvoidreceive(Stringevent);}

💬白话:每个设备都认识中介者,发消息走中介者,收消息靠自己。

3.3 具体同事类:电视、窗帘、灯光

publicclassTVextendsComponent{publicTV(Mediatormediator){super(mediator);}publicvoidturnOn(){System.out.println("【电视】打开");send("tv_on");}@Overridepublicvoidreceive(Stringevent){if("curtain_closed".equals(event)){System.out.println("【电视】检测到窗帘已关闭,调整画面亮度");}}}publicclassCurtainextendsComponent{publicCurtain(Mediatormediator){super(mediator);}publicvoidclose(){System.out.println("【窗帘】关闭");send("curtain_closed");}@Overridepublicvoidreceive(Stringevent){if("tv_on".equals(event)){this.close();}}}publicclassLightextendsComponent{publicLight(Mediatormediator){super(mediator);}publicvoiddim(){System.out.println("【灯光】调暗");}publicvoidoff(){System.out.println("【灯光】关闭");}@Overridepublicvoidreceive(Stringevent){if("tv_on".equals(event)){this.dim();}}}

💬白话:电视只管自己打开并发出“我开了”的消息,至于窗帘和灯光要做什么,电视完全不知道——这些逻辑全在中介者里。

3.4 具体中介者:智能中控

publicclassSmartHomeMediatorimplementsMediator{privateTVtv;privateCurtaincurtain;privateLightlight;publicvoidsetTv(TVtv){this.tv=tv;}publicvoidsetCurtain(Curtaincurtain){this.curtain=curtain;}publicvoidsetLight(Lightlight){this.light=light;}@Overridepublicvoidnotify(Componentsender,Stringevent){switch(event){case"tv_on":// 电视打开 → 窗帘关闭,灯光调暗curtain.receive("tv_on");light.receive("tv_on");break;case"curtain_closed":// 窗帘关闭 → 电视收到通知tv.receive("curtain_closed");break;}}}

💬白话:中介者是“大脑”,所有联动规则集中在这里。电视打开时顺便关窗帘、调灯光——这条规则只写一次,在中介者里。

3.5 客户端

SmartHomeMediatormediator=newSmartHomeMediator();TVtv=newTV(mediator);Curtaincurtain=newCurtain(mediator);Lightlight=newLight(mediator);mediator.setTv(tv);mediator.setCurtain(curtain);mediator.setLight(light);// 用户打开电视tv.turnOn();// 输出:// 【电视】打开// 【窗帘】关闭// 【灯光】调暗// 【电视】检测到窗帘已关闭,调整画面亮度

所有联动规则全部集中在SmartHomeMediator.notify(),新增设备或修改规则只需改动中介者类,同事类无需修改。


4. 代码实现:聊天室(经典面试场景)

聊天室是中介者模式的另一个经典例子。用户不直接发消息给另一个用户,而是发送给聊天室,由聊天室广播给所有用户。

4.1 中介者

publicinterfaceChatRoom{voidsendMessage(Usersender,Stringmessage);voidaddUser(Useruser);}

4.2 具体中介者

publicclassChatRoomImplimplementsChatRoom{privateList<User>users=newArrayList<>();@OverridepublicvoidaddUser(Useruser){users.add(user);}@OverridepublicvoidsendMessage(Usersender,Stringmessage){for(Useruser:users){if(user!=sender){user.receive(sender.getName(),message);}}}}

💬白话:聊天室就是中介者,收到一条消息后广播给所有人(除了发送者自己)。

4.3 同事类:用户

publicclassUser{privateStringname;privateChatRoomroom;publicUser(Stringname,ChatRoomroom){this.name=name;this.room=room;room.addUser(this);}publicStringgetName(){returnname;}publicvoidsend(Stringmessage){System.out.println(name+" 发送: "+message);room.sendMessage(this,message);}publicvoidreceive(Stringfrom,Stringmessage){System.out.println(name+" 收到来自 "+from+" 的消息: "+message);}}

💬白话:用户只知道聊天室,不知道其他用户的存在。发消息走聊天室,收消息也是聊天室送来的。

4.4 客户端

ChatRoomroom=newChatRoomImpl();Useralice=newUser("Alice",room);Userbob=newUser("Bob",room);Usercharlie=newUser("Charlie",room);alice.send("大家好!");// Alice 发送: 大家好!// Bob 收到来自 Alice 的消息: 大家好!// Charlie 收到来自 Alice 的消息: 大家好!

5. 优缺点一览

优点缺点
解耦:同事类之间零依赖,从网状变星型中介者可能膨胀:所有交互逻辑集中在中介者中,可能成为“上帝类”
集中控制:交互逻辑统一管控,修改方便中介者复杂度上升:随着同事类增加,维护成本快速上升
简化测试:同事类可脱离具体中介者独立测试性能瓶颈:所有通信都经过中介者,高并发场景可能成为瓶颈
符合单一职责:同事类只负责自身业务,交互逻辑交给中介者

6. 中介者模式 vs 外观模式

这两个模式都充当“中间人”角色,但目的完全不同:

对比维度中介者模式外观模式
目的协调多个对象之间的双向交互为子系统提供单向统一入口
通信方向多对多 → 一对多(同事 ↔ 中介者 ↔ 同事)单向调用(客户端 → 外观 → 子系统)
关注点对象之间如何协作简化客户端调用
子系统感知同事类知道中介者的存在子系统不知道外观存在
典型应用聊天室、设备联动、MVC 的 ControllerSLF4J、JdbcTemplate、微服务网关

💡 外观是“统一入口”,中介者是“通信枢纽”。外观不知道客户端的存在,中介者知道所有同事。


7. 框架与实践中的应用

7.1 Spring MVC:DispatcherServlet

DispatcherServlet是 Spring MVC 的核心,它充当了 Controller、ViewResolverHandlerMapping等众多组件之间的中介者。各组件不直接交互,而是通过DispatcherServlet协调请求分派、视图解析、异常处理等流程。

7.2 消息中间件(RabbitMQ、Kafka)

消息中间件的 Broker 就是典型的中介者。生产者与消费者不直接连接,而是通过 Broker 中转消息,Broker 负责路由、广播、持久化等交互逻辑。

7.3 微服务注册中心(Eureka、Nacos)

在微服务架构中,服务之间不直接写死地址,而是通过注册中心发现彼此。注册中心就是中介者,服务只与注册中心通信,获取其他服务实例的信息。


8. 面试必问 + 面试官追问连环炮

基础必问

  • 中介者模式的核心角色?Mediator(中介者)、Colleague(同事类)。
  • 中介者模式如何解耦?→ 将对象间的多对多依赖转为一对多依赖,同事类只依赖中介者。
  • Spring MVC 中的DispatcherServlet是什么模式?→ 中介者模式,协调所有 MVC 组件。

面试官追问

  • “中介者和外观有什么区别?”
    👉 外观是单向简化调用入口,中介者是双向协调交互。外观不知道客户端的存在,中介者知道所有同事。
  • “中介者膨胀了怎么办?”
    👉 引入多个中介者分层协作,按业务域拆分。如智能家居可以拆分为“影音中控”、“环境中控”等。
  • “消息队列是中介者模式吗?”
    👉 是。生产者与消费者不直接通信,通过 Broker 中转,Broker 就是中介者。

🎉恭喜:如果你能立刻说出DispatcherServlet是中介者模式,消息队列 Broker 也是中介者思想,并清楚中介者与外观的本质区别,你已经掌握了行为型模式中“化网为星”的设计精髓。


9. 六大设计原则在中介者模式中的体现

设计原则在中介者模式中的体现
单一职责原则(SRP)同事类负责自身业务,中介者负责交互协调,职责分离
开闭原则(OCP)新增同事类通常无需修改中介者;新增交互规则只需修改中介者
里氏替换原则(LSP)同事类都遵循抽象Colleague接口,可替换
依赖倒置原则(DIP)同事类依赖抽象Mediator接口,不依赖具体中介者
接口隔离原则(ISP)Mediator接口定义精简,仅暴露notify()
迪米特法则(LoD)同事类只与中介者通信,完全不知道其他同事的存在

🧭 《Java 23 种设计模式:从踩坑到精通》快速导航

  • 开篇:系列介绍与目录
  • 上一篇:迭代器模式 —— 遍历集合,为什么不直接暴露内部结构?
  • 当前:中介者模式 —— 对象关系太乱?请一位“中间人”(你在这里)
  • 下一篇:备忘录模式 —— 快照与撤销,给对象装一个“后悔药” 🚧 即将发布
  • 创建型模式汇总:单例、工厂、建造者、原型
  • 结构型模式汇总:适配器、装饰器、代理……
  • 行为型模式汇总:观察者、策略、模板方法……

🔔 关注《Java 23 种设计模式:从踩坑到精通》,用 25 篇文章彻底吃透设计模式。
📦福利预告:全系列代码及 UML 源码将在完结时统一打包开放,点击「关注」「收藏」第一时间获取。
🚀下一篇:备忘录模式:快照与撤销,给对象装一个“后悔药”!🚧 即将发布,敬请关注!

📌 除了设计模式,我也在深挖智能物流实战(WMS、托盘调度、机器学习落地)。欢迎点击头像,看看专栏 《出版社物流WMS智能调度实战》。技术相通,思路可鉴。