中介者模式:让对象之间的沟通变得优雅
说实话,中介者模式是我在实际项目中用得比较多的模式之一。为什么?因为随着系统越来越复杂,对象之间的交互关系会变得像蜘蛛网一样,牵一发而动全身。这时候,中介者模式就像是一个交通指挥中心,让所有车辆(对象)都按照规则行驶,而不是各自乱窜。
什么是中介者模式?
中介者模式,说白了就是用一个中介对象来封装一系列对象之间的交互。这些对象不需要直接互相引用,而是通过中介者来沟通。你想想看,这就像我们生活中的房产中介——买房的人不需要直接跟卖房的人讨价还价,一切都通过中介来协调。
我记得有一次接手一个老项目,里面十几个UI组件互相调用,改一个按钮的逻辑要排查七八个文件。我当时就想,这要是早用中介者模式,能省多少事啊。
模式结构
中介者模式的结构其实很清晰,主要有这么几个角色:
- Mediator(抽象中介者):定义通信接口,声明同事对象之间的交互方法
- ConcreteMediator(具体中介者):实现中介者接口,协调各个同事对象的交互
- Colleague(抽象同事类):定义同事对象的公共接口,持有中介者的引用
- ConcreteColleague(具体同事类):实现自己的业务逻辑,通过中介者与其他同事通信
核心思想:每个同事对象只知道自己和中介者的关系,不需要知道其他同事的存在。这样就把多对多的交互关系,简化成了一对多的关系。
SVG结构图
代码实现
来看一个实际的例子。假设我们有一个聊天室系统,用户之间需要发送消息。如果用传统方式,每个用户都要知道其他所有用户的存在,这显然不现实。
// 抽象中介者
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网关:各个微服务通过网关来通信,而不是直接互相调用。
嗯,这里要注意一点:中介者模式不是万能的。如果你的对象之间交互关系很简单,比如只有两三个对象互相调用,那完全没必要引入中介者。过度设计有时候比没有设计更可怕。
与其他模式的关系
中介者模式和观察者模式有时候容易被混淆。我简单说一下区别:
- 观察者模式:是一对多的关系,一个主题变化,通知所有观察者。通信是单向的。
- 中介者模式:是多对多的关系,所有同事通过中介者双向通信。通信是双向的。
说白了,观察者模式适合"广播"场景,中介者模式适合"协调"场景。在实际项目中,我有时候会把两者结合起来用——用观察者模式实现中介者内部的事件通知机制。
好了,中介者模式就讲到这里。记住它的核心:让对象之间不直接通信,而是通过中介者来协调。这样你的系统会变得更加灵活、更容易维护。