GoF设计模式——中介者模式

本文是【GoF设计模式】系列第15篇,更多内容欢迎关注公众号:咖啡八杯

前言

为什么需要中介者模式?

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

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

java 复制代码
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(具体同事类):实现同事类接口,每个同事类只知道自己行为,通过中介者与其他同事交互

classDiagram direction BT class Mediator { <<interface>> +register(colleague: Colleague) +send(message: String, colleague: Colleague) } class ConcreteMediator { -colleagues: List~Colleague~ +register(colleague: Colleague) +send(message: String, colleague: Colleague) } class Colleague { <<abstract>> #mediator: Mediator +send(message: String) +receive(message: String) } class ConcreteColleagueA { +send(message: String) +receive(message: String) } class ConcreteColleagueB { +send(message: String) +receive(message: String) } ConcreteMediator ..|> Mediator : 实现 ConcreteColleagueA --|> Colleague : 继承 ConcreteColleagueB --|> Colleague : 继承 Mediator o--> Colleague : 持有同事列表 Colleague --> Mediator : 持有中介者引用

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

实现

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

标准实现

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

java 复制代码
// 抽象中介者
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,通过中介者与其他同事交互

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

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

java 复制代码
// 抽象中介者
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 方法,设备类不变。

总结

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

什么时候用

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

什么时候不用

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

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

相似模式区分

总览

模式 核心意图 典型场景
中介者 协调多个对象间的复杂交互 智能家居中控、聊天室、GUI组件联动
观察者 一对多的通知机制 事件监听、消息订阅、数据绑定
门面 为子系统提供统一入口 API封装、SDK入口、简化调用

中介者 vs 观察者

维度 中介者模式 观察者模式
核心意图 集中协调多对象间的双向交互 一对多的单向通知
结构差异 中介者知道所有同事,同事只知道中介者 主题知道所有观察者,观察者只知道主题
关注点 对象间的交互规则和联动逻辑 状态变化的通知分发
典型场景 智能家居中控、聊天室、工作流引擎 事件监听、消息订阅、数据绑定

逐步区分法

  1. 如果对象间需要双向交互(A变化影响B,B变化可能再影响A)→ 选中介者
  2. 如果只是单向通知(主题变化通知观察者,观察者不反向影响主题)→ 选观察者
  3. 如果联动规则复杂需要集中管理 → 选中介者

简单记忆口诀:中介者管双向协调,观察者管单向通知。

推荐:大多数场景下,复杂联动用中介者,简单通知用观察者。Spring事件机制是观察者的变体,但可以用于简单联动场景。

中介者 vs 门面

维度 中介者模式 门面模式
核心意图 协调多对象间的交互,降低耦合 为复杂子系统提供统一入口,简化调用
结构差异 中介者参与业务逻辑,协调对象间的交互 门面只是封装调用入口,不参与子系统内部逻辑
关注点 对象间的交互规则 子系统的使用接口
典型场景 聊天室、GUI组件联动、工作流引擎 API封装、SDK入口、简化配置

逐步区分法

  1. 如果需要协调多个对象间的交互(对象间有联动)→ 选中介者
  2. 如果只是简化调用入口(提供一个统一接口调用多个子系统)→ 选门面
  3. 如果对象需要反向通知中介者 → 选中介者(门面是单向的)

简单记忆口诀:中介者管交互,门面管入口。

推荐:门面用于简化外部调用,中介者用于协调内部交互。两者可以组合使用:门面作为外部入口,中介者协调内部逻辑。

练习题目

智能家居中控系统

题目描述:小明正在设计一个智能家居系统,系统中有灯(Light)、窗帘(Curtain)、空调(AC)三种设备,它们通过智能家居中控(中介者)来协调联动。设备之间不直接通信,所有联动逻辑由中控负责。

中控的联动规则:

  • 空调开启 → 自动关闭窗帘(避免冷气流失)
  • 空调关闭 → 自动打开窗帘
  • 窗帘关闭 → 自动开灯(补充采光)
  • 窗帘打开 → 自动关灯(自然光足够)

注意:联动可能产生连锁反应。例如开启空调 → 关闭窗帘 → 开灯。同一设备在同一次连锁中状态只改变一次,避免循环触发。

输入描述:第一行包含三个字符串,分别是灯、窗帘、空调的名称,用空格分隔。第二行包含三个字符串,分别是灯、窗帘、空调的初始状态(on 或 off),用空格分隔。接下来每行包含一个操作,格式为设备名 操作(操作为 on 或 off),直到输入结束。

输出描述:对于每个操作,按联动触发顺序输出每个状态发生变化的设备,格式为设备名 on 或设备名 off。若操作未导致状态变化(设备已在目标状态),则不输出。

输入示例

复制代码
Light Curtain AC
off on off
AC on
AC off
Curtain off

输出示例

复制代码
AC on
Curtain off
Light on
AC off
Curtain on
Light off
Curtain off
Light on

解题思路:本题的核心是中介者模式的连锁反应机制。

角色对应

  • Mediator(抽象中介者)Mediator 接口,定义 send 方法
  • ConcreteMediator(具体中介者)SmartHomeMediator,实现联动规则(空调→窗帘→灯)
  • Colleague(抽象同事类)Device 抽象类,持有中介者引用,提供 sendreceive 方法
  • ConcreteColleague(具体同事类)LightCurtainAC,具体设备实现

连锁反应机制

  1. 用户操作设备(如开启空调)→ 调用 device.send("on")
  2. send 方法更新状态并输出,然后通知中介者 mediator.send("on", this)
  3. 中介者根据联动规则,调用相关设备的 receive 方法(如关闭窗帘)
  4. receive 方法更新状态并输出,再次通知中介者,形成递归连锁
  5. 避免循环触发:在 sendreceive 中检查 if (!status.equals(message)),如果状态已经是目标状态则不处理
java 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] names = line.split(" ");
        line = sc.nextLine();
        String[] status = line.split(" ");

        Mediator mediator = new SmartHomeMediator();

        Light light = new Light(mediator, names[0], status[0]);
        Curtain curtain = new Curtain(mediator, names[1], status[1]);
        AC ac = new AC(mediator, names[2], status[2]);

        mediator.setLight(light);
        mediator.setCurtain(curtain);
        mediator.setAc(ac);

        Map<String, Device> map = new HashMap<>();
        map.put(names[0], light);
        map.put(names[1], curtain);
        map.put(names[2], ac);

        while (sc.hasNext()) {
            String name = sc.next();
            String s = sc.next();
            Device d = map.get(name);
            d.send(s);
        }
    }
}

// 抽象中介者
interface Mediator {
    public void send(String message, Device device);
}

// 具体中介者:智能家居中控
class SmartHomeMediator implements Mediator {
    private Light light;
    private Curtain curtain;
    private AC ac;

    public void setLight(Light light) { this.light = light; }
    public void setCurtain(Curtain curtain) { this.curtain = curtain; }
    public void setAc(AC ac) { this.ac = ac; }

    public void send(String message, Device device) {
        // 空调状态变化触发窗帘联动
        if (device instanceof AC) {
            if (message.equals("on")) {
                curtain.receive("off");  // 规则1:空调开 → 关窗帘
            } else {
                curtain.receive("on");   // 规则2:空调关 → 开窗帘
            }
        }
        // 窗帘状态变化触发灯联动
        else if (device instanceof Curtain) {
            if (message.equals("on")) {
                light.receive("off");    // 规则4:窗帘开 → 关灯
            } else {
                light.receive("on");     // 规则3:窗帘关 → 开灯
            }
        }
        // 灯状态变化不触发联动
    }
}

// 抽象同事类:设备基类
abstract class Device {
    protected Mediator mediator;
    protected String name;
    protected String status;

    public Device(Mediator mediator, String name, String status) {
        this.mediator = mediator;
        this.name = name;
        this.status = status;
    }

    public String getName() { return name; }
    public String getStatus() { return status; }

    // 用户操作触发状态变化
    public void send(String message) {
        if (!status.equals(message)) {
            System.out.println(name + " " + message);
            status = message;
            mediator.send(message, this); // 通知中介者
        }
    }

    // 中介者通知触发状态变化
    public void receive(String message) {
        if (!status.equals(message)) {
            System.out.println(name + " " + message);
            status = message;
            mediator.send(message, this); // 状态变化后通知中介者,形成连锁
        }
    }
}

// 具体同事类:灯
class Light extends Device {
    public Light(Mediator mediator, String name, String status) {
        super(mediator, name, status);
    }
}

// 具体同事类:窗帘
class Curtain extends Device {
    public Curtain(Mediator mediator, String name, String status) {
        super(mediator, name, status);
    }
}

// 具体同事类:空调
class AC extends Device {
    public AC(Mediator mediator, String name, String status) {
        super(mediator, name, status);
    }
}

扩展:实际项目中的中介者模式

Spring事件机制(ApplicationEventPublisher)

Spring的事件机制本质上是中介者模式的变体:ApplicationEventPublisher 作为中介者,事件监听器作为同事类,通过事件机制解耦组件间的交互。

场景:订单系统中,订单创建后需要通知库存系统扣减库存、通知支付系统生成支付单、通知消息系统发送通知。如果订单直接依赖库存、支付、消息系统,耦合度极高。

角色对照

  • MediatorApplicationEventPublisher(Spring容器提供)
  • Colleague :各个事件监听器(@EventListener 标注的方法)
  • 事件对象:同事之间传递的消息载体
java 复制代码
// 事件对象:订单创建事件
public class OrderCreatedEvent extends ApplicationEvent {
    private String orderId;
    private BigDecimal amount;

    public OrderCreatedEvent(Object source, String orderId, BigDecimal amount) {
        super(source);
        this.orderId = orderId;
        this.amount = amount;
    }

    public String getOrderId() { return orderId; }
    public BigDecimal getAmount() { return amount; }
}

// 同事类A:库存服务监听器
@Service
public class InventoryEventListener {
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("扣减库存,订单号:" + event.getOrderId());
        // 调用库存服务扣减库存
    }
}

// 同事类B:支付服务监听器
@Service
public class PaymentEventListener {
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("生成支付单,金额:" + event.getAmount());
        // 调用支付服务生成支付单
    }
}

// 同事类C:消息服务监听器
@Service
public class MessageEventListener {
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("发送订单创建通知,订单号:" + event.getOrderId());
        // 调用消息服务发送通知
    }
}

// 订单服务:发布事件(不依赖任何监听器)
@Service
public class OrderService {
    @Autowired
    private ApplicationEventPublisher publisher;  // 注入中介者

    public void createOrder(String orderId, BigDecimal amount) {
        // 创建订单逻辑...
        System.out.println("订单创建成功:" + orderId);

        // 发布事件,通知所有监听器(不需要知道有哪些监听器)
        publisher.publishEvent(new OrderCreatedEvent(this, orderId, amount));
    }
}

关键点ApplicationEventPublisher 作为中介者,发布事件后自动通知所有监听器;监听器通过 @EventListener 注解声明自己关心的消息类型;订单服务只需要发布事件,不需要知道有哪些监听器,耦合度降到最低。

GUI对话框组件协调

GUI界面中多个控件(按钮、文本框、下拉框)之间的联动逻辑复杂时,使用中介者集中管理交互规则。

场景:用户注册对话框包含用户名输入框、密码输入框、确认密码框、注册按钮。联动规则:用户名输入后检查是否已存在,密码和确认密码不一致时提示错误,所有验证通过后注册按钮才可用。

角色对照

  • MediatorDialogMediator 接口
  • ConcreteMediatorRegisterDialogMediator,实现具体联动规则
  • ColleagueUIComponent 抽象类,所有UI组件的基类
  • ConcreteColleagueTextBoxButton 等具体组件
java 复制代码
// 抽象中介者
interface DialogMediator {
    public void notify(UIComponent component, String event);
}

// 抽象同事类:UI组件基类
abstract class UIComponent {
    protected DialogMediator mediator;
    protected String name;

    public UIComponent(DialogMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }

    public String getName() { return name; }

    // 组件状态变化时通知中介者
    public void changed() {
        mediator.notify(this, "changed");
    }

    public abstract void setEnabled(boolean enabled);
    public abstract String getValue();
}

// 具体同事类:文本框
class TextBox extends UIComponent {
    private String value = "";

    public TextBox(DialogMediator mediator, String name) {
        super(mediator, name);
    }

    public void setValue(String value) {
        this.value = value;
        changed();  // 值变化时通知中介者
    }

    public String getValue() { return value; }

    public void setEnabled(boolean enabled) {
        System.out.println(name + (enabled ? " 启用" : " 禁用"));
    }
}

// 具体同事类:按钮
class Button extends UIComponent {
    private boolean enabled = false;

    public Button(DialogMediator mediator, String name) {
        super(mediator, name);
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
        System.out.println(name + (enabled ? " 启用" : " 禁用"));
    }

    public String getValue() { return String.valueOf(enabled); }

    public void click() {
        if (enabled) {
            System.out.println(name + " 被点击");
            mediator.notify(this, "click");
        }
    }
}

// 具体中介者:注册对话框
class RegisterDialogMediator implements DialogMediator {
    private TextBox usernameBox;
    private TextBox passwordBox;
    private TextBox confirmBox;
    private Button registerButton;
    private Label messageLabel;

    public RegisterDialogMediator(TextBox usernameBox, TextBox passwordBox,
                                   TextBox confirmBox, Button registerButton,
                                   Label messageLabel) {
        this.usernameBox = usernameBox;
        this.passwordBox = passwordBox;
        this.confirmBox = confirmBox;
        this.registerButton = registerButton;
        this.messageLabel = messageLabel;
    }

    public void notify(UIComponent component, String event) {
        // 用户名变化 → 检查是否已存在
        if (component == usernameBox && event.equals("changed")) {
            String username = usernameBox.getValue();
            if (isUsernameExists(username)) {
                messageLabel.setText("用户名已存在");
                registerButton.setEnabled(false);
            } else {
                messageLabel.setText("");
                validateForm();
            }
        }
        // 密码或确认密码变化 → 检查是否一致
        else if ((component == passwordBox || component == confirmBox)
                 && event.equals("changed")) {
            String password = passwordBox.getValue();
            String confirm = confirmBox.getValue();
            if (!password.isEmpty() && !confirm.isEmpty() && !password.equals(confirm)) {
                messageLabel.setText("两次密码不一致");
                registerButton.setEnabled(false);
            } else {
                messageLabel.setText("");
                validateForm();
            }
        }
        // 注册按钮点击 → 执行注册
        else if (component == registerButton && event.equals("click")) {
            doRegister();
        }
    }

    private void validateForm() {
        boolean valid = !usernameBox.getValue().isEmpty()
                     && !passwordBox.getValue().isEmpty()
                     && passwordBox.getValue().equals(confirmBox.getValue())
                     && !isUsernameExists(usernameBox.getValue());
        registerButton.setEnabled(valid);
    }

    private boolean isUsernameExists(String username) {
        // 模拟检查用户名是否存在
        return "admin".equals(username);
    }

    private void doRegister() {
        System.out.println("注册成功:" + usernameBox.getValue());
    }
}

关键点 :每个组件只知道自己状态,通过 changed() 通知中介者;中介者根据变化类型执行不同的联动规则;如果联动规则变化(如增加邮箱验证),只需修改中介者,组件类不变。

MVC架构中的Controller

MVC架构中,Controller作为中介者协调Model和View的交互,避免Model和View直接耦合。

场景:用户列表页面,View显示用户列表,Model提供用户数据。用户点击删除按钮时,View通知Controller,Controller调用Model删除用户,Model返回结果后Controller更新View。

角色对照

  • MediatorUserController
  • ColleagueUserModel(数据层)、UserView(视图层)
java 复制代码
// Model:用户数据(同事类A)
class UserModel {
    private List<String> users = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie"));

    public List<String> getUsers() { return new ArrayList<>(users); }

    public boolean deleteUser(String username) {
        return users.remove(username);
    }
}

// View:用户视图(同事类B)
class UserView {
    public void showUsers(List<String> users) {
        System.out.println("用户列表:" + users);
    }

    public void showMessage(String message) {
        System.out.println("提示:" + message);
    }

    // 用户点击删除按钮,通知Controller
    public void onDeleteClicked(String username, UserController controller) {
        controller.handleDelete(username);
    }
}

// Controller:中介者
class UserController {
    private UserModel model;
    private UserView view;

    public UserController(UserModel model, UserView view) {
        this.model = model;
        this.view = view;
    }

    // 协调Model和View的交互
    public void handleDelete(String username) {
        boolean success = model.deleteUser(username);  // 调用Model
        if (success) {
            view.showMessage("删除成功:" + username);   // 更新View
            view.showUsers(model.getUsers());           // 刷新列表
        } else {
            view.showMessage("删除失败:" + username + " 不存在");
        }
    }

    public void showUserList() {
        view.showUsers(model.getUsers());
    }
}

关键点:Model只负责数据操作,不关心View如何显示;View只负责显示和接收用户操作,不关心Model如何处理数据;Controller作为中介者协调两者,Model和View通过Controller通信。

多人聊天室

聊天室是中介者模式的经典应用:聊天室服务器作为中介者,用户作为同事类,用户之间不直接通信,都通过聊天室转发消息。

场景:多人聊天室,用户A发送消息时,聊天室服务器转发给所有其他用户。用户加入或退出时,聊天室通知所有用户。

角色对照

  • MediatorChatRoom 接口
  • ConcreteMediatorConcreteChatRoom,维护用户列表,转发消息
  • ColleagueUser 抽象类
  • ConcreteColleagueChatUser,具体用户实现
java 复制代码
// 抽象中介者
interface ChatRoom {
    public void register(User user);
    public void send(String message, User sender);
}

// 抽象同事类:用户基类
abstract class User {
    protected ChatRoom chatRoom;
    protected String name;

    public User(ChatRoom chatRoom, String name) {
        this.chatRoom = chatRoom;
        this.name = name;
    }

    public String getName() { return name; }

    public abstract void receive(String message, String senderName);
    public abstract void send(String message);
}

// 具体中介者:聊天室
class ConcreteChatRoom implements ChatRoom {
    private List<User> users = new ArrayList<>();

    public void register(User user) {
        users.add(user);
        System.out.println(user.getName() + " 加入聊天室");
        // 通知其他用户
        for (User u : users) {
            if (u != user) {
                u.receive(user.getName() + " 加入了聊天室", "系统");
            }
        }
    }

    public void send(String message, User sender) {
        // 转发给除发送者外的所有用户
        for (User u : users) {
            if (u != sender) {
                u.receive(message, sender.getName());
            }
        }
    }
}

// 具体同事类:聊天用户
class ChatUser extends User {
    public ChatUser(ChatRoom chatRoom, String name) {
        super(chatRoom, name);
    }

    public void receive(String message, String senderName) {
        System.out.println("[" + name + " 收到] " + senderName + ":" + message);
    }

    public void send(String message) {
        System.out.println("[" + name + " 发送] " + message);
        chatRoom.send(message, this);  // 通过中介者转发
    }
}

// 使用示例
public class ChatRoomDemo {
    public static void main(String[] args) {
        ChatRoom room = new ConcreteChatRoom();

        User alice = new ChatUser(room, "Alice");
        User bob = new ChatUser(room, "Bob");
        User charlie = new ChatUser(room, "Charlie");

        room.register(alice);  // Alice加入,无其他用户
        room.register(bob);    // Bob加入,通知Alice
        room.register(charlie);// Charlie加入,通知Alice和Bob

        alice.send("大家好!");  // Alice发消息,Bob和Charlie收到
        bob.send("Hi Alice!");   // Bob发消息,Alice和Charlie收到
    }
}

关键点 :用户之间不直接通信,都通过聊天室转发,降低耦合;聊天室维护用户列表,负责消息转发和用户加入/离开通知;如果需要增加私聊功能,只需修改中介者的 send 方法增加目标参数。

技术交流 & 更多原创内容,关注公众号:咖啡八杯

相关推荐
lizhongxuan3 小时前
多Agent之间的区别
后端
青石路5 小时前
记一次多JDK版本问题的排查,一坑套一坑,差点没爬上来
java
杨充5 小时前
1.面向对象设计思想
后端
IT_陈寒6 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro6 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗6 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端
她的男孩7 小时前
后台接口加密别只会 HTTPS,ForgeAdmin 的 RSA + SM4/AES 源码拆解
后端·面试·开源
极光技术熊7 小时前
Spring AI 从入门到精通:构建你的 AI 开发知识体系
后端·github
程序员cxuan7 小时前
一句话,让你用上 GPT-5.6
人工智能·后端·程序员