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设计模式系列文章。😊