一、中介者模式:对象间解耦、MVC中的中介者

中介者模式,说白了就是给一堆互相调用的对象找个「中间人」。

我刚开始做项目时,经常遇到这样的场景:几个模块之间互相持有引用,A调B,B调C,C又调A……代码改一处,牵一发动全身。后来我意识到,这种网状结构迟早会变成维护噩梦。

中介者模式就是来解决这个问题的。它把多对多的交互,转变成一对多的交互——所有对象只跟中介者通信,中介者负责协调。

1.1 什么是中介者模式

中介者模式(Mediator Pattern)定义了一个封装对象间交互行为的对象。它让对象之间不再显式引用彼此,从而降低耦合。

你想想看,现实中的房产中介就是典型例子。房东和租客不需要直接认识,中介帮他们完成信息匹配、谈判、签约。代码里的中介者也是这个道理。

核心思想: 用一个中介对象来封装一系列对象的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

1.2 模式结构

角色 职责
Mediator(抽象中介者) 定义通信接口,用于各同事对象之间的通信
ConcreteMediator(具体中介者) 实现中介者接口,协调各同事对象的交互逻辑
Colleague(抽象同事类) 定义同事对象的公共接口,持有中介者引用
ConcreteColleague(具体同事类) 每个同事类只知道自己的行为,不关心其他同事

1.3 代码示例:聊天室

我拿一个聊天室的例子来说明。用户之间发消息,如果每个用户都持有其他用户的引用,那代码会非常混乱。用中介者模式就清爽多了。

// 抽象中介者
public abstract class Mediator {
    public abstract void sendMessage(String message, User user);
}

// 具体中介者 - 聊天室
public class ChatRoom extends Mediator {
    private List<User> users = new ArrayList<>();

    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 Mediator mediator;
    protected String name;

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

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

// 具体同事类
public class ChatUser extends User {
    public ChatUser(Mediator mediator, String name) {
        super(mediator, name);
    }

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

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

// 客户端使用
public class Client {
    public static void main(String[] args) {
        ChatRoom chatRoom = new ChatRoom();

        User user1 = new ChatUser(chatRoom, "张三");
        User user2 = new ChatUser(chatRoom, "李四");
        User user3 = new ChatUser(chatRoom, "王五");

        chatRoom.addUser(user1);
        chatRoom.addUser(user2);
        chatRoom.addUser(user3);

        user1.send("大家好!");
        user2.send("欢迎新同学!");
    }
}

运行结果:

张三 发送消息: 大家好!
李四 收到消息: 大家好!
王五 收到消息: 大家好!
李四 发送消息: 欢迎新同学!
张三 收到消息: 欢迎新同学!
王五 收到消息: 欢迎新同学!

你看,每个用户只跟聊天室打交道,不需要知道其他用户的存在。这就是解耦。

1.4 MVC中的中介者

说到中介者模式,就不得不提MVC架构。我个人觉得,MVC就是中介者模式最经典的实践。

  • View(视图):负责展示数据,不直接操作数据源
  • Controller(控制器):扮演中介者角色,接收用户输入,协调Model和View
  • Model(模型):负责业务逻辑和数据,不关心谁来展示它

我在项目中遇到过这样的场景:一个表单页面,用户点击提交按钮,View需要验证数据、调用接口、更新页面状态。如果没有Controller,这些逻辑全塞在View里,代码很快就变成一坨。

用MVC之后,View只负责渲染和事件绑定,Controller负责调度,Model负责数据。各司其职,改起来也轻松。

我的习惯: 在Spring MVC项目中,Controller层尽量保持薄,只做参数校验和路由转发。真正的业务逻辑放到Service层。这样Controller作为中介者,职责单一,测试也方便。

1.5 中介者模式的应用场景

  1. 多个对象之间存在复杂的引用关系:比如GUI中的多个组件互相影响
  2. 想复用某个对象,但它的交互逻辑太复杂:把交互抽出来放到中介者里
  3. 系统需要解耦,让各模块独立演化:中介者模式天然支持这一点

1.6 中介者模式的优缺点

优点 缺点
减少类之间的直接耦合 中介者可能变得庞大复杂
将多对多交互简化为一对多 中介者出问题会影响所有同事
符合迪米特法则 增加了系统的复杂度
避坑指南: 我曾经在一个项目中过度使用中介者模式,把所有交互逻辑都塞到一个中介者类里。结果这个类变得又臭又长,维护起来比原来还痛苦。后来我拆分成多个小中介者,每个负责一个业务域,才解决问题。

1.7 中介者模式与观察者模式的区别

这两个模式容易混淆。我简单说一下区别:

  • 中介者模式:对象之间通过中介者通信,中介者知道所有对象
  • 观察者模式:一个对象(主题)通知多个观察者,观察者之间不知道彼此

说白了,中介者模式是「点对点」的协调,观察者模式是「一对多」的通知。实际项目中,两者经常结合使用。

1.8 核心逻辑图

中介者模式核心逻辑 中介者 同事A 同事B 同事C 所有同事只与中介者通信,不直接引用彼此 中介者负责协调各同事的交互逻辑 网状结构 → 星型结构,降低耦合

1.9 总结

中介者模式的核心价值就一句话:把多对多的混乱交互,变成一对多的清晰调度

我在实际项目中,一般会在以下情况考虑使用中介者模式:

  • 多个对象之间有复杂的交互逻辑
  • 交互逻辑经常变化,需要集中管理
  • 希望各模块能独立测试和复用

但也要注意,不要为了用模式而用模式。如果只有两三个对象交互,直接调用反而更简单。模式是工具,不是目的。

一句话记住: 中介者模式 = 对象间解耦 + 交互逻辑集中管理。MVC中的Controller就是最好的例子。

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