Java设计模式-中介者模式

Java设计模式-中介者模式

模式概述

中介者模式简介

核心思想 :通过引入一个中介对象(协调者),将原本对象之间的直接交互转化为通过中介对象间接交互。中介对象封装了所有对象之间的通信逻辑,使得对象之间无需显式引用彼此,从而降低系统的耦合度,提高灵活性和可维护性。

模式类型:行为型模式(Behavioral Pattern)。

作用

  • 解耦对象交互:对象间通过中介者通信,避免直接依赖,减少类间耦合;
  • 集中控制逻辑:将复杂的交互逻辑集中到中介者中,便于统一管理和修改;
  • 提高扩展性:新增对象只需与中介者交互,无需修改现有对象;
  • 简化对象职责:对象只需关注自身核心逻辑,无需处理与其他对象的协调。

典型应用场景

  • GUI组件交互:如窗口中的按钮、文本框、下拉框,通过中介者(窗口管理器)协调事件响应;
  • 聊天系统:用户(同事)通过聊天服务器(中介者)转发消息,避免用户间直接连接;
  • 交通信号灯系统:信号灯(中介者)控制车辆(同事)的通行状态;
  • 分布式系统协调:微服务架构中通过服务注册中心(中介者)协调服务间调用;
  • 游戏角色协作:游戏中的角色(如战士、法师)通过队长(中介者)发布战斗指令。

我认为:中介者模式就像团队中的"项目经理",原本需要成员间直接沟通的任务,现在由项目经理统一协调,既减少了成员间的干扰,又让任务流程更清晰可控。

课程目标

  • 理解中介者模式的核心思想和经典应用场景
  • 识别应用场景,使用中介者模式解决功能要求
  • 了解中介者模式的优缺点

核心组件

角色-职责表

角色 职责 示例类名
抽象中介者(Mediator) 定义协调同事对象的接口(如notify(Colleague colleague, String message))。 ChatServer(聊天服务器接口)
具体中介者(ConcreteMediator) 实现抽象中介者的方法,持有同事对象集合,协调具体交互逻辑。 ConcreteChatServer(具体聊天服务器)
抽象同事类(Colleague) 定义与其他同事交互的接口(如send(String message)receive(String message)),并持有中介者引用。 User(用户抽象类)
具体同事类(ConcreteColleague) 实现抽象同事类的方法,通过中介者与其他同事通信。 StudentUser(学生用户)、TeacherUser(教师用户)

类图

下面是一个简化的类图表示,展示了中介者模式中的主要角色及其交互方式:
持有用户列表 依赖中介者 <<interface>> ChatServer +adduser(User user) +notify(User sender, String message) ConcreteChatServer -List users +adduser(User user) +notify(User sender, String message) User -String name -ChatServer server +getName() +setServer(ChatServer server) +send(String message) +receive(String message) NormalUser +NormalUser(String name) +send(String message) +receive(String message)


传统实现 VS 中介者模式

案例需求

案例背景:设计一个多人聊天系统,支持用户发送消息给其他所有用户。传统方式中,用户直接调用其他用户的接收方法发送消息,导致用户间强耦合;使用中介者模式后,用户仅与聊天服务器(中介者)交互,由服务器转发消息。

传统实现(痛点版)

代码实现

java 复制代码
// 传统方式:用户间直接交互(强耦合)
public class User {
    private String name;
    private List<User> friends; // 直接持有其他用户引用

    public User(String name) {
        this.name = name;
        this.friends = new ArrayList<>();
    }

    // 添加好友(需双向绑定)
    public void addFriend(User friend) {
        if (!friends.contains(friend)) {
            friends.add(friend);
            friend.friends.add(this);
        }
    }

    // 发送消息给所有好友(直接调用好友的receive方法)
    public void send(String message) {
        for (User friend : friends) {
            friend.receive(name + "说:" + message);
        }
    }

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

// 客户端使用(强耦合问题)
public class Client {
    public static void main(String[] args) {
        User alice = new User("Alice");
        User bob = new User("Bob");
        User charlie = new User("Charlie");

        // 用户需互相添加好友(耦合)
        alice.addFriend(bob);
        alice.addFriend(charlie);
        bob.addFriend(alice);
        bob.addFriend(charlie);
        charlie.addFriend(alice);
        charlie.addFriend(bob);

        // Alice发送消息(需依赖Bob和Charlie的存在)
        alice.send("今天聚餐去哪里?"); 
        // 输出:
        // Bob收到:Alice说:今天聚餐去哪里?
        // Charlie收到:Alice说:今天聚餐去哪里?
    }
}

痛点总结

  • 强耦合 :用户间需互相持有引用(friends列表),新增用户时需手动绑定所有好友,扩展性差;
  • 逻辑分散 :消息转发逻辑分散在每个用户的send()方法中,若需修改转发规则(如过滤敏感词),需修改所有用户类;
  • 维护困难:用户间交互逻辑复杂,调试时需跟踪多个类的调用链,容易出错。

中介者模式 实现(优雅版)

代码实现

java 复制代码
// 1. 抽象中介者:聊天服务器接口
public interface ChatServer {
    void adduser(User user); // 注册用户
    void notify(User sender, String message); // 转发消息
}

// 2. 具体中介者:实现消息转发逻辑
public class ConcreteChatServer implements ChatServer {
    private List<User> users = new ArrayList<>();

    @Override
    public void adduser(User user) {
        users.add(user);
        user.setServer(this); // 用户绑定中介者
    }

    @Override
    public void notify(User sender, String message) {
        for (User user : users) {
            if (user != sender) { // 不回传给发送者自己
                user.receive(sender.getName() + "说:" + message);
            }
        }
    }
}

// 3. 抽象同事类:用户
public abstract class User {
    protected String name;
    protected ChatServer server; // 持有中介者引用

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

    public String getName() {
        return name;
    }

    public void setServer(ChatServer server) {
        this.server = server;
    }

    public abstract void send(String message); // 发送消息(通过中介者)
    public abstract void receive(String message); // 接收消息
}

// 4. 具体同事类:普通用户
public class NormalUser extends User {
    public NormalUser(String name) {
        super(name);
    }

    @Override
    public void send(String message) {
        if (server != null) {
            server.notify(this, message); // 通过中介者转发消息
        }
    }

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

// 客户端使用(解耦后的效果)
public class Client {
    public static void main(String[] args) {
        // 创建中介者(聊天服务器)
        ChatServer server = new ConcreteChatServer();

        // 创建用户并注册到服务器(无需互相绑定)
        User alice = new NormalUser("Alice");
        User bob = new NormalUser("Bob");
        User charlie = new NormalUser("Charlie");
        server.adduser(alice);
        server.adduser(bob);
        server.adduser(charlie);

        // Alice发送消息(仅需调用中介者,无需知道其他用户存在)
        alice.send("今天聚餐去哪里?"); 
        // 输出:
        // Bob收到:Alice说:今天聚餐去哪里?
        // Charlie收到:Alice说:今天聚餐去哪里?
    }
}

优势

  • 低耦合 :用户(User)仅依赖中介者(ChatServer),无需持有其他用户的引用;
  • 逻辑集中 :消息转发规则(如过滤敏感词、分组发送)集中在ConcreteChatServer中,修改时只需调整中介者;
  • 易扩展 :新增用户(如AdminUser)只需实现User接口并注册到服务器,无需修改现有代码;
  • 维护便捷 :交互逻辑集中在中介者,调试时只需关注中介者的notify()方法。

局限

  • 中介者复杂度:若对象交互逻辑非常复杂(如多人协作编辑文档),中介者可能变得庞大,需拆分或分层;
  • 性能开销:所有消息需经过中介者转发,高并发场景下可能成为性能瓶颈(可通过异步消息队列优化);
  • 过度设计风险:若对象间交互简单(如仅两个对象),直接调用比引入中介者更高效。

模式变体

  • 全局中介者(单例中介者):中介者通过单例模式全局共享(如聊天服务器),确保所有同事对象访问同一中介者;
  • 分层中介者:复杂系统中使用多个中介者分层协调(如前端中介者处理UI交互,后端中介者处理业务逻辑);
  • 事件驱动中介者:中介者基于事件总线(如Guava EventBus)实现,同事对象通过发布/订阅事件通信;
  • 智能中介者:中介者增加业务逻辑(如消息过滤、权限校验),提供更复杂的协调能力;
  • 临时中介者:针对特定任务动态创建中介者(如文件传输任务的临时协调者),任务结束后销毁。

最佳实践

建议 理由
中介者职责单一 中介者应仅负责协调交互,避免包含业务逻辑(如用户验证),保持职责清晰。
同事类轻量 同事类应尽量保持简单,仅处理自身核心逻辑(如用户发送消息),依赖中介者处理复杂交互。
接口隔离 抽象中介者和抽象同事类通过接口定义,降低实现类的耦合(如不同聊天服务器实现同一接口)。
避免循环依赖 中介者与同事类之间避免双向强引用(如同事类持有中介者,中介者持有同事类集合),防止内存泄漏。
异常处理 中介者需处理同事对象的异常(如消息发送失败),避免单个同事异常影响整体交互。
性能优化 高并发场景下,中介者可使用异步消息队列(如Kafka)转发消息,提升系统吞吐量。

一句话总结

中介者模式通过引入协调中心,将对象间的直接交互转化为间接通信,有效降低了系统耦合度,使对象职责更清晰、扩展更灵活。

如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊