中介者模式:让对象之间的沟通变得优雅

说实话,中介者模式是我在实际项目中用得比较多的模式之一。为什么?因为随着系统越来越复杂,对象之间的交互关系会变得像蜘蛛网一样,牵一发而动全身。这时候,中介者模式就像是一个交通指挥中心,让所有车辆(对象)都按照规则行驶,而不是各自乱窜。

什么是中介者模式?

中介者模式,说白了就是用一个中介对象来封装一系列对象之间的交互。这些对象不需要直接互相引用,而是通过中介者来沟通。你想想看,这就像我们生活中的房产中介——买房的人不需要直接跟卖房的人讨价还价,一切都通过中介来协调。

我记得有一次接手一个老项目,里面十几个UI组件互相调用,改一个按钮的逻辑要排查七八个文件。我当时就想,这要是早用中介者模式,能省多少事啊。

模式结构

中介者模式的结构其实很清晰,主要有这么几个角色:

  • Mediator(抽象中介者):定义通信接口,声明同事对象之间的交互方法
  • ConcreteMediator(具体中介者):实现中介者接口,协调各个同事对象的交互
  • Colleague(抽象同事类):定义同事对象的公共接口,持有中介者的引用
  • ConcreteColleague(具体同事类):实现自己的业务逻辑,通过中介者与其他同事通信

核心思想:每个同事对象只知道自己和中介者的关系,不需要知道其他同事的存在。这样就把多对多的交互关系,简化成了一对多的关系。

SVG结构图

中介者模式结构图 Mediator ConcreteMediator ConcreteColleague1 ConcreteColleague2 ConcreteColleague3 抽象中介者 具体中介者 具体同事类 虚线表示:同事之间不直接通信,全部通过中介者协调

代码实现

来看一个实际的例子。假设我们有一个聊天室系统,用户之间需要发送消息。如果用传统方式,每个用户都要知道其他所有用户的存在,这显然不现实。

// 抽象中介者
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 abstract class User {
    protected ChatMediator mediator;
    protected String name;
    
    public User(ChatMediator mediator, String name) {
        this.mediator = mediator;
        this.name = name;
    }
    
    public abstract void send(String message);
    public abstract void receive(String message);
}

// 具体同事类
public class ConcreteUser extends User {
    public ConcreteUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }
    
    @Override
    public void send(String message) {
        System.out.println(this.name + " 发送消息: " + message);
        mediator.sendMessage(message, this);
    }
    
    @Override
    public void receive(String message) {
        System.out.println(this.name + " 收到消息: " + message);
    }
}

// 使用示例
public class Demo {
    public static void main(String[] args) {
        ChatMediator chatRoom = new ChatRoom();
        
        User alice = new ConcreteUser(chatRoom, "Alice");
        User bob = new ConcreteUser(chatRoom, "Bob");
        User charlie = new ConcreteUser(chatRoom, "Charlie");
        
        chatRoom.addUser(alice);
        chatRoom.addUser(bob);
        chatRoom.addUser(charlie);
        
        alice.send("大家好!");
        // 输出:
        // Alice 发送消息: 大家好!
        // Bob 收到消息: 大家好!
        // Charlie 收到消息: 大家好!
    }
}

我的经验:在实际项目中,我习惯把中介者的接口设计得尽量通用。比如上面的例子,如果后续需要支持私聊、群聊、文件传输等功能,只需要扩展中介者的接口,而不需要修改同事类的代码。

优缺点分析

优点 缺点
  • 降低了对象之间的耦合度,每个对象只需要知道中介者
  • 将多对多的交互简化为一对多的交互
  • 符合迪米特法则(最少知道原则)
  • 新增同事类时,只需要修改中介者,符合开闭原则
  • 中介者可能会变得非常庞大,承担过多的职责
  • 如果中介者出问题,整个系统都会受影响
  • 增加了系统的复杂度,需要额外维护中介者

避坑指南:我曾经在一个项目中过度使用中介者模式,把所有业务逻辑都塞进了中介者里。结果中介者变成了一个几千行的"上帝类",改一个功能要翻半天代码。记住,中介者只是协调者,不是业务逻辑的容器。

应用场景

中介者模式适合用在哪些地方?我总结了几种典型场景:

  • GUI组件交互:比如一个表单里有多个输入框、下拉框、按钮,它们之间需要联动。用中介者模式可以避免组件之间互相引用。
  • 聊天系统:用户之间的消息传递,通过聊天服务器(中介者)来转发。
  • 机场调度系统:飞机之间不需要直接通信,全部通过塔台(中介者)来协调起降。
  • 微服务架构中的API网关:各个微服务通过网关来通信,而不是直接互相调用。

嗯,这里要注意一点:中介者模式不是万能的。如果你的对象之间交互关系很简单,比如只有两三个对象互相调用,那完全没必要引入中介者。过度设计有时候比没有设计更可怕。

与其他模式的关系

中介者模式和观察者模式有时候容易被混淆。我简单说一下区别:

  • 观察者模式:是一对多的关系,一个主题变化,通知所有观察者。通信是单向的。
  • 中介者模式:是多对多的关系,所有同事通过中介者双向通信。通信是双向的。

说白了,观察者模式适合"广播"场景,中介者模式适合"协调"场景。在实际项目中,我有时候会把两者结合起来用——用观察者模式实现中介者内部的事件通知机制。

好了,中介者模式就讲到这里。记住它的核心:让对象之间不直接通信,而是通过中介者来协调。这样你的系统会变得更加灵活、更容易维护。


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