为什么需要中介者模式?

假设在设计一个智能家居系统,家里有空调、窗帘、灯三种设备。业务规则是:空调开启时自动关闭窗帘(避免冷气流失),窗帘关闭时自动开灯(补充采光)。

最直觉的写法是让设备之间直接互相调用:

class AirConditioner { private Curtain curtain; private Light light; public void turnOn() { // 空调开启逻辑 curtain.close(); // 直接调用窗帘 } } class Curtain { private Light light; public void close() { // 窗帘关闭逻辑 light.turnOn(); // 直接调用灯 } }

这种写法的问题很快暴露:空调需要知道窗帘,窗帘需要知道灯,设备之间形成复杂的网状依赖。如果新增一个设备(如加湿器),需要修改所有相关设备的代码。更麻烦的是,如果业务规则变了(比如空调开启时也要开灯),就得改空调的代码,违反开闭原则。

中介者模式解决的就是这种"多个对象之间存在复杂联动关系"的耦合问题。把所有联动规则集中到一个中介者对象里,设备只跟中介者通信,互不认识。

概念

中介者模式(Mediator Pattern)是一种行为型设计模式,核心思想是用一个中介对象封装一系列对象之间的交互,使各对象不需要显式地互相引用,从而使其耦合松散,而且可以独立改变它们之间的交互

可以把它想象成航空管制塔台:每架飞机(同事对象)不需要知道其他飞机的位置和航线,只需要向塔台(中介者)报告自己的状态,塔台根据全局信息协调所有飞机的起降和飞行路径。飞机之间互不通信,全部通过塔台协调。

中介者模式涉及四个角色:

  • Mediator(抽象中介者):定义中介者接口,用于各同事对象之间的通信
  • ConcreteMediator(具体中介者):实现中介者接口,负责协调各同事对象的交互关系,需要知道所有同事类
  • Colleague(抽象同事类):定义同事类接口,维护一个对中介者对象的引用
  • ConcreteColleague(具体同事类):实现同事类接口,每个同事类只知道自己行为,通过中介者与其他同事交互

实现

继承

继承

持有同事列表

持有中介者引用

«interface»

Mediator

+register(colleague: Colleague)

+send(message: String, colleague: Colleague)

ConcreteMediator

-colleagues: List<Colleague>

+register(colleague: Colleague)

+send(message: String, colleague: Colleague)

«abstract»

Colleague

#mediator: Mediator

+send(message: String)

+receive(message: String)

ConcreteColleagueA

+send(message: String)

+receive(message: String)

ConcreteColleagueB

+send(message: String)

+receive(message: String)

图中各类之间的关系:Mediator接口定义了registersend方法,ConcreteMediator实现该接口并持有List<Colleague>Colleague抽象类持有Mediator引用并通过它发送消息——同事类之间不直接通信,全部通过中介者协调。

实现

GoF 的标准实现中,中介者维护所有同事的引用,同事通过中介者转发消息。当同事状态变化时,通知中介者,中介者根据业务规则决定通知哪些其他同事。

标准实现

定义一个Mediator接口作为抽象中介者,声明register(注册同事)和send(转发消息)方法。Colleague作为抽象同事类,持有中介者引用,提供send(发送消息)和receive(接收消息)方法。具体中介者ConcreteMediator维护同事列表,在send方法中实现消息转发策略。具体同事类ConcreteColleagueAConcreteColleagueB通过中介者与其他同事交互。

// 抽象中介者 interface Mediator { public void register(Colleague colleague); public void send(String message, Colleague colleague); } // 抽象同事类 abstract class Colleague { protected Mediator mediator; public Colleague(Mediator mediator) { this.mediator = mediator; } public abstract void receive(String message); public abstract void send(String message); } // 具体中介者 class ConcreteMediator implements Mediator { private List<Colleague> colleagues = new ArrayList<>(); public void register(Colleague colleague) { colleagues.add(colleague); } public void send(String message, Colleague colleague) { // 转发给除发送者外的所有同事 for (Colleague c : colleagues) { if (c != colleague) { c.receive(message); } } } } // 具体同事类A class ConcreteColleagueA extends Colleague { public ConcreteColleagueA(Mediator mediator) { super(mediator); } public void receive(String message) { System.out.println("ColleagueA 收到消息: " + message); } public void send(String message) { System.out.println("ColleagueA 发送消息: " + message); mediator.send(message, this); } } // 具体同事类B class ConcreteColleagueB extends Colleague { public ConcreteColleagueB(Mediator mediator) { super(mediator); } public void receive(String message) { System.out.println("ColleagueB 收到消息: " + message); } public void send(String message) { System.out.println("ColleagueB 发送消息: " + message); mediator.send(message, this); } }

角色对照

  • Mediator(抽象中介者)Mediator接口,定义registersend方法
  • ConcreteMediator(具体中介者)ConcreteMediator,维护同事列表,实现消息转发策略
  • Colleague(抽象同事类)Colleague抽象类,持有中介者引用,提供sendreceive方法
  • ConcreteColleague(具体同事类)ConcreteColleagueAConcreteColleagueB,通过中介者与其他同事交互

关键点:同事类只负责自身状态,通过中介者转发消息;中介者维护所有同事引用,根据业务规则决定消息转发策略。同事之间不直接通信,全部通过中介者协调。

引入一个具体场景:智能家居系统,空调、窗帘、灯三种设备通过中控(中介者)协调联动。空调开启时自动关闭窗帘(避免冷气流失),窗帘关闭时自动开灯(补充采光)。

// 抽象中介者 interface SmartHomeMediator { public void register(Device device); public void notify(String event, Device device); } // 抽象同事类:设备基类 abstract class Device { protected SmartHomeMediator mediator; protected String name; protected boolean state; public Device(SmartHomeMediator mediator, String name) { this.mediator = mediator; this.name = name; this.state = false; } public String getName() { return name; } public boolean getState() { return state; } public void setState(boolean state) { this.state = state; System.out.println(name + " " + (state ? "开启" : "关闭")); mediator.notify(state ? "on" : "off", this); } public abstract void handleEvent(String event); } // 具体中介者:智能家居中控 class ConcreteSmartHomeMediator implements SmartHomeMediator { private List<Device> devices = new ArrayList<>(); public void register(Device device) { devices.add(device); } public void notify(String event, Device device) { // 空调开启 → 关闭窗帘 if (device instanceof AirConditioner && event.equals("on")) { for (Device d : devices) { if (d instanceof Curtain) { d.setState(false); } } } // 窗帘关闭 → 开启灯 if (device instanceof Curtain && event.equals("off")) { for (Device d : devices) { if (d instanceof Light) { d.setState(true); } } } } } // 具体同事类:空调 class AirConditioner extends Device { public AirConditioner(SmartHomeMediator mediator) { super(mediator, "空调"); } public void handleEvent(String event) { // 空调不处理其他设备的事件 } } // 具体同事类:窗帘 class Curtain extends Device { public Curtain(SmartHomeMediator mediator) { super(mediator, "窗帘"); } public void handleEvent(String event) { // 窗帘不处理其他设备的事件 } } // 具体同事类:灯 class Light extends Device { public Light(SmartHomeMediator mediator) { super(mediator, "灯"); } public void handleEvent(String event) { // 灯不处理其他设备的事件 } }

角色对照

  • Mediator(抽象中介者)SmartHomeMediator接口,定义registernotify方法
  • ConcreteMediator(具体中介者)ConcreteSmartHomeMediator,维护设备列表,实现联动规则
  • Colleague(抽象同事类)Device抽象类,持有中介者引用,状态变化时通知中介者
  • ConcreteColleague(具体同事类)AirConditionerCurtainLight,具体设备实现

关键点:设备状态变化时调用setState,在setState中通知中介者;中介者根据事件类型和设备类型执行联动规则;如果业务规则变化(比如空调开启时也要开灯),只需修改中介者的notify方法,设备类不变。

总结

本质:用一个中介对象封装多个对象之间的交互,将网状依赖转化为星形结构。

什么时候用

  • 多个对象之间存在复杂的网状依赖关系
  • 需要集中管理对象间的交互规则
  • 想要降低对象间的耦合度,提高可维护性

什么时候不用

  • 对象之间只有简单的两两交互,引入中介者反而增加复杂度
  • 性能要求极高,中介者转发消息的开销不可接受
  • 中介者本身会变得过于庞大复杂(上帝对象)

简单记忆:中介者管协调,同事只管报;规则集中改,耦合自然少。