中介者模式:集中对象交互逻辑

FreeGuideOnline 最新 2026-06-18

中介者模式:集中对象交互逻辑

在软件系统中,当多个对象之间相互引用、彼此通信时,对象间的耦合会变得错综复杂,形成一张难以维护的“网状结构”。中介者模式(Mediator Pattern)正是为了化解这种混乱而生,它引入一个中介者对象,将所有对象之间的交互逻辑集中管理,使对象之间不再直接显式引用,而是通过中介者间接沟通。


1. 模式概述

意图:用一个中介对象来封装一系列对象之间的交互,使各对象无需显式地相互引用,从而使其耦合松散,并可以独立地改变它们之间的交互。

核心思想:将对象间的“多对多”关系转化为“一对多”关系。原本需要互相通信的同事对象,只认识中介者,所有消息都经由中介者转发,交互逻辑从中剥离出来,集中存放在中介者内部。

现实类比
‎- 机场塔台:飞机之间不会直接通信来协调起降,而是通过塔台(中介者)统一调度。
‎- 聊天室:用户不直接给其他用户发消息,而是把消息发送到聊天室(中介者),由后者广播给所有人或特定人。


2. 模式结构

中介者模式通常包含以下几种角色:

角色 说明
Mediator(抽象中介者) 定义同事对象之间通信的接口,通常包含一个或多个通信方法。
ConcreteMediator(具体中介者) 实现中介者接口,维护一个对各个同事对象的引用,负责协调它们之间的交互,封装具体的业务逻辑。
Colleague(抽象同事类) 定义同事对象的接口,持有对中介者的引用,通过该引用与其他同事通信。
ConcreteColleague(具体同事类) 具体的同事对象,实现自己的业务方法,需要与其他同事通信时,触发中介者的相应方法。

结构图示意(文字描述):

        Mediator (interface)
        |
        |----- ConcreteMediator
        |
        |
ColleagueA ---> Mediator
ColleagueB ---> Mediator
  • 每一个 Colleague 内部都维护一个 Mediator 引用。
  • ConcreteMediator 内部持有所有 Colleague 的引用,根据需要调用它们的方法。
  • 同事之间互不直接持有引用,所有交互请求都提交给中介者。

3. 代码示例(Java)

以下用例模拟一个简易的智能家居系统:传感器(Sensor)检测到环境变化后,需要通过控制中心(Mediator)通知报警器(Alarm)和显示器(Display)。

3.1 定义抽象中介者

// 抽象中介者
interface SmartHomeMediator {
    void register(Device device);
    void eventOccurred(String eventType, Device device);
}

// 抽象同事类
abstract class Device {
    protected SmartHomeMediator mediator;
    protected String name;

    public Device(SmartHomeMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
        mediator.register(this);
    }

    public abstract void sendEvent(String event);
    public abstract void receiveEvent(String event);
}

3.2 定义具体同事类

class Sensor extends Device {
    public Sensor(SmartHomeMediator mediator, String name) {
        super(mediator, name);
    }

    public void detectMotion() {
        System.out.println(name + "检测到移动!");
        sendEvent("motion_detected");
    }

    @Override
    public void sendEvent(String event) {
        mediator.eventOccurred(event, this);
    }

    @Override
    public void receiveEvent(String event) {
        // 传感器一般不需要接收事件,但保留方法以保持统一接口
    }
}

class Alarm extends Device {
    public Alarm(SmartHomeMediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    public void sendEvent(String event) {
        mediator.eventOccurred(event, this);
    }

    @Override
    public void receiveEvent(String event) {
        if (event.equals("motion_detected")) {
            System.out.println(name + ":发出警报声!");
        }
    }
}

class Display extends Device {
    public Display(SmartHomeMediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    public void sendEvent(String event) {
        mediator.eventOccurred(event, this);
    }

    @Override
    public void receiveEvent(String event) {
        if (event.equals("motion_detected")) {
            System.out.println(name + ":显示“有人闯入”");
        }
    }
}

3.3 实现具体中介者

class ConcreteSmartHomeMediator implements SmartHomeMediator {
    private Sensor sensor;
    private Alarm alarm;
    private Display display;

    @Override
    public void register(Device device) {
        if (device instanceof Sensor) {
            this.sensor = (Sensor) device;
        } else if (device instanceof Alarm) {
            this.alarm = (Alarm) device;
        } else if (device instanceof Display) {
            this.display = (Display) device;
        }
    }

    @Override
    public void eventOccurred(String eventType, Device device) {
        if (eventType.equals("motion_detected") && device instanceof Sensor) {
            if (alarm != null) {
                alarm.receiveEvent(eventType);
            }
            if (display != null) {
                display.receiveEvent(eventType);
            }
        }
    }
}

3.4 客户端调用

public class Client {
    public static void main(String[] args) {
        ConcreteSmartHomeMediator mediator = new ConcreteSmartHomeMediator();

        Sensor sensor = new Sensor(mediator, "门口红外传感器");
        Alarm alarm = new Alarm(mediator, "客厅警铃");
        Display display = new Display(mediator, "中控显示屏");

        sensor.detectMotion();
    }
}

运行结果

门口红外传感器检测到移动!
客厅警铃:发出警报声!
中控显示屏:显示“有人闯入”

通过中介者,Sensor 无需直接依赖 AlarmDisplay,所有协调逻辑集中在 ConcreteSmartHomeMediator 中,添加新设备(如手机推送)时只需修改中介者即可。


4. 中介者模式的优缺点

✅ 优点

  • 降低耦合度:各个同事对象之间解耦,它们只依赖于抽象中介者,可以独立变化和复用。
  • 集中控制交互逻辑:所有交互关系集中在一个中介者里,符合“单一职责原则”,便于理解、维护和修改。
  • 减少子类生成:无需为每一组对象交互创建新的协作类,中介者可以动态组合对象的交互行为。
  • 简化对象协议:用一对多的中介者交互替代多对多的网状交互,更容易理解。

❌ 缺点

  • 中介者可能变得庞大复杂:随着同事对象增多和交互逻辑复杂化,具体中介者可能会变成一个难以维护的“上帝类”。
  • 中介者成为瓶颈:如果中介者出现问题,整个系统的通信将瘫痪。
  • 同事类依然需要通信:虽然同事之间解耦,但它们仍需要知道中介者的存在,并未完全消除耦合。

5. 适用场景

  • 一组对象以定义良好但复杂的方式进行通信,相互依赖关系混乱且难以理解。
  • 一个对象引用了多个其他对象,并且直接与这些对象通信,导致该对象难以复用。
  • 想定制一个分布在多个类中的行为,而又不想生成太多子类。
  • 在 GUI 开发中,经常使用中介者模式来协调多个 UI 组件之间的交互(如对话框中的按钮、复选框、文本框的联动)。
  • 在聊天室、消息中间件、微服务中的消息代理等典型场景中,可见中介者模式的实际应用。

6. 与其他模式的关系

模式 关系
观察者模式 中介者可以通过观察者模式来实现与各同事之间的通信。同事类可以充当观察者,中介者充当目标,当事件发生时通知所有订阅该事件的同事。
外观模式 外观模式为子系统提供统一接口,但子系统内部仍可直接交互;中介者则禁止子系统组件直接交互,所有通信必须通过中介者。
命令模式 发送请求时可以使用命令对象封装请求并传递给中介者,中介者根据请求类型进行调度,实现更灵活的逻辑解耦。

7. 实现要点与最佳实践

  • 接口设计:抽象中介者应定义同事之间共通的通信接口,保持方法通用。可以由具体中介者决定如何分发事件。
  • 避免中介者职责过重:当具体中介者过于庞大时,考虑将部分交互逻辑拆分到其他辅助类中,或者使用多个中介者分工协作(例如引入“中介者链”)。
  • 使用事件类型枚举:传递事件时尽量使用明确的类型(如枚举),避免字符串硬编码,提高代码可维护性。
  • 双向通信:同事类既可以发送事件给中介者,也可以从中介者接收事件,设计时注意区分通知方法与业务方法。
  • 同事类的注册:可以在构造函数中由同事对象自行注册到中介者,也可以由中介者主动管理同事列表,根据实际情况选择。

8. 总结

中介者模式通过将对象间的网状交互星状化,有效降低了系统的耦合度,使交互逻辑清晰集中。它适合于对象群复杂通信的场景,但需警惕“上帝中介者”的出现。正确使用该模式,可以让代码结构更简洁、更易于扩展和维护,是面向对象设计中应对复杂交互关系的利器。