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

📅 2026/7/6 17:40:29
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 MVCDispatcherServlet7.2 消息中间件RabbitMQ、Kafka7.3 微服务注册中心Eureka、Nacos8. 面试必问 面试官追问连环炮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.mediatormediator;}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.tvtv;}publicvoidsetCurtain(Curtaincurtain){this.curtaincurtain;}publicvoidsetLight(Lightlight){this.lightlight;}Overridepublicvoidnotify(Componentsender,Stringevent){switch(event){casetv_on:// 电视打开 → 窗帘关闭灯光调暗curtain.receive(tv_on);light.receive(tv_on);break;casecurtain_closed:// 窗帘关闭 → 电视收到通知tv.receive(curtain_closed);break;}}}白话中介者是“大脑”所有联动规则集中在这里。电视打开时顺便关窗帘、调灯光——这条规则只写一次在中介者里。3.5 客户端SmartHomeMediatormediatornewSmartHomeMediator();TVtvnewTV(mediator);CurtaincurtainnewCurtain(mediator);LightlightnewLight(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{privateListUserusersnewArrayList();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.namename;this.roomroom;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 客户端ChatRoomroomnewChatRoomImpl();UseralicenewUser(Alice,room);UserbobnewUser(Bob,room);UsercharlienewUser(Charlie,room);alice.send(大家好);// Alice 发送: 大家好// Bob 收到来自 Alice 的消息: 大家好// Charlie 收到来自 Alice 的消息: 大家好5. 优缺点一览优点缺点解耦同事类之间零依赖从网状变星型中介者可能膨胀所有交互逻辑集中在中介者中可能成为“上帝类”集中控制交互逻辑统一管控修改方便中介者复杂度上升随着同事类增加维护成本快速上升简化测试同事类可脱离具体中介者独立测试性能瓶颈所有通信都经过中介者高并发场景可能成为瓶颈符合单一职责同事类只负责自身业务交互逻辑交给中介者6. 中介者模式 vs 外观模式这两个模式都充当“中间人”角色但目的完全不同对比维度中介者模式外观模式目的协调多个对象之间的双向交互为子系统提供单向统一入口通信方向多对多 → 一对多同事 ↔ 中介者 ↔ 同事单向调用客户端 → 外观 → 子系统关注点对象之间如何协作简化客户端调用子系统感知同事类知道中介者的存在子系统不知道外观存在典型应用聊天室、设备联动、MVC 的 ControllerSLF4J、JdbcTemplate、微服务网关 外观是“统一入口”中介者是“通信枢纽”。外观不知道客户端的存在中介者知道所有同事。7. 框架与实践中的应用7.1 Spring MVCDispatcherServletDispatcherServlet是 Spring MVC 的核心它充当了 Controller、ViewResolver、HandlerMapping等众多组件之间的中介者。各组件不直接交互而是通过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接口不依赖具体中介者接口隔离原则ISPMediator接口定义精简仅暴露notify()迪米特法则LoD同事类只与中介者通信完全不知道其他同事的存在 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录上一篇迭代器模式 —— 遍历集合为什么不直接暴露内部结构当前中介者模式 —— 对象关系太乱请一位“中间人”你在这里下一篇备忘录模式 —— 快照与撤销给对象装一个“后悔药” 即将发布创建型模式汇总单例、工厂、建造者、原型结构型模式汇总适配器、装饰器、代理……行为型模式汇总观察者、策略、模板方法…… 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。下一篇备忘录模式快照与撤销给对象装一个“后悔药” 即将发布敬请关注 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》。技术相通思路可鉴。