中介者模式:聊天室里的“和事佬”

说实话,中介者模式是我在项目中用得最频繁的模式之一。为什么?因为只要系统里对象一多,通信就会乱成一锅粥。你想想看,如果每个对象都要知道其他对象的存在,那代码的耦合度简直不敢想象。

中介者模式的核心思想很简单:用一个中介对象来封装一系列对象的交互。说白了,就是让对象之间不再直接“说话”,而是通过一个中间人来传达。这个中间人就是中介者。

业务场景:聊天室

聊天室是最经典的中介者模式案例。用户之间不直接通信,而是通过聊天室服务器(中介者)来转发消息。每个用户只需要知道服务器的地址,不需要知道其他用户的存在。

我在项目中遇到过类似场景——一个内部协作平台,多个模块需要互相通知状态变更。如果让模块之间直接调用,那代码会变成一团乱麻。后来我用中介者模式重构,所有模块只跟一个“事件总线”通信,清爽多了。

MVC 中的 Controller

MVC 架构里,Controller 就是 Model 和 View 的中介者。View 不直接操作 Model,Model 也不直接更新 View。所有交互都通过 Controller 来协调。这就是中介者模式的典型应用。

核心结构

中介者模式涉及以下几个角色:

  • Mediator(中介者):定义通信接口,负责协调各同事对象的交互。
  • ConcreteMediator(具体中介者):实现中介者接口,维护同事对象的引用,实现具体的协调逻辑。
  • Colleague(同事):每个同事对象都持有中介者的引用,需要通信时调用中介者的方法。

嗯,这里要注意:同事对象之间不能有直接引用。所有通信必须经过中介者。这是模式的核心约束。

代码示例:聊天室实现

我们来看一个简单的聊天室实现。先定义中介者接口:

// 中介者接口
public interface ChatMediator {
    void sendMessage(String message, User user);
    void addUser(User user);
}

然后实现具体中介者——聊天室服务器:

// 具体中介者
public class ChatRoom implements ChatMediator {
    private List<User> users = new ArrayList<>();

    @Override
    public void addUser(User user) {
        users.add(user);
    }

    @Override
    public void sendMessage(String message, User sender) {
        for (User user : users) {
            // 消息不发送给自己
            if (user != sender) {
                user.receive(message);
            }
        }
    }
}

接下来是同事对象——用户:

// 同事类
public class User {
    private String name;
    private ChatMediator mediator;

    public User(String name, ChatMediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

    public void send(String message) {
        System.out.println(name + " 发送消息: " + message);
        mediator.sendMessage(message, this);
    }

    public void receive(String message) {
        System.out.println(name + " 收到消息: " + message);
    }
}

客户端使用:

public class Client {
    public static void main(String[] args) {
        ChatMediator chatRoom = new ChatRoom();

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

        chatRoom.addUser(alice);
        chatRoom.addUser(bob);
        chatRoom.addUser(charlie);

        alice.send("大家好!");
        bob.send("嗨,Alice!");
    }
}

运行结果:

Alice 发送消息: 大家好!
Bob 收到消息: 大家好!
Charlie 收到消息: 大家好!
Bob 发送消息: 嗨,Alice!
Alice 收到消息: 嗨,Alice!
Charlie 收到消息: 嗨,Alice!

中介者模式的核心逻辑图

下面这张 SVG 图展示了中介者模式的核心交互逻辑:

中介者模式核心交互图 中介者(ChatRoom) 同事1(Alice) 同事2(Bob) 同事3(Charlie) sendMessage() receive() receive() 禁止直接通信 所有同事只与中介者通信,不直接交互 中介者负责消息的转发和协调 ✓ 降低耦合度 | ✓ 简化对象交互 | ✓ 易于扩展

避坑指南

我曾经在一个项目中过度使用中介者模式,结果中介者变成了一个“上帝对象”,什么逻辑都往里面塞。最后中介者本身变得臃肿不堪,维护起来比直接耦合还痛苦。

这里分享几个经验:

  • 中介者不要包揽一切:只做协调和转发,不要把业务逻辑也塞进去。
  • 同事对象保持简单:同事只负责自己的行为,不要依赖中介者做太多事情。
  • 考虑性能:如果通信非常频繁,中介者可能成为瓶颈。这时候可以考虑事件驱动或消息队列。

核心要点:中介者模式的核心价值在于“解耦”。它让对象之间的多对多关系,变成了对象与中介者之间的一对多关系。虽然增加了一个中间层,但换来了系统的可维护性和可扩展性。

个人习惯:我一般在以下情况使用中介者模式:

  • 一组对象之间通信复杂,且通信逻辑经常变化
  • 想复用某个对象,但它依赖太多其他对象
  • 需要集中控制对象之间的交互行为

注意:不要为了用模式而用模式。如果对象之间只有简单的两两通信,直接调用反而更清晰。中介者模式适合“多对多”的复杂场景。

实际项目中的应用

我记得在一个电商系统中,订单、库存、支付、物流等多个模块需要协同工作。如果让它们直接互相调用,那代码会变成蜘蛛网。我引入了一个“交易协调器”作为中介者,所有模块只跟协调器通信。后来新增了优惠券模块,只需要在协调器里加几行代码就行,其他模块完全不用改。

这就是中介者模式的魅力——让系统在变化中保持稳定

说白了,中介者模式就是给对象们请了一个“和事佬”。大家有事找和事佬,别自己吵吵。这样系统才能井井有条。

公众号:蓝海资料掘金营,微信deep3321