中介者模式 (Mediator Pattern)
用一个中介对象来封装一系列的对象交互
模式定义
中介者模式是一种行为型设计模式,它用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式将多对多的复杂交互关系转化为一对多的关系,简化了对象之间的通信。
模式结构
graph TD
A[Mediator] --> B[Colleague]
B --> C[ConcreteColleague1]
B --> D[ConcreteColleague2]
C --> A
D --> A
实现方式
基础实现
定义中介者接口和同事类抽象类,实现具体中介者和具体同事类。
// 中介者接口
public interface ChatMediator {
void sendMessage(String msg, User user);
void addUser(User user);
}
// 同事类抽象类
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator med, String name) {
this.mediator = med;
this.name = name;
}
public abstract void send(String msg);
public abstract void receive(String msg);
}
// 具体中介者
class ChatMediatorImpl implements ChatMediator {
private List users;
public ChatMediatorImpl() {
this.users = new ArrayList<>();
}
@Override
public void addUser(User user) {
this.users.add(user);
}
@Override
public void sendMessage(String msg, User user) {
for (User u : this.users) {
// 不向发送者自己发送消息
if (u != user) {
u.receive(msg);
}
}
}
}
// 具体同事类
class UserImpl extends User {
public UserImpl(ChatMediator med, String name) {
super(med, name);
}
@Override
public void send(String msg) {
System.out.println(this.name + ": 发送消息=" + msg);
mediator.sendMessage(msg, this);
}
@Override
public void receive(String msg) {
System.out.println(this.name + ": 收到消息=" + msg);
}
}
使用示例
public class MediatorPatternDemo {
public static void main(String[] args) {
ChatMediator mediator = new ChatMediatorImpl();
User user1 = new UserImpl(mediator, "张三");
User user2 = new UserImpl(mediator, "李四");
User user3 = new UserImpl(mediator, "王五");
User user4 = new UserImpl(mediator, "赵六");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
mediator.addUser(user4);
user1.send("大家好!");
System.out.println();
user2.send("你好,张三!");
}
}
经典案例
1. Java Timer类
Java中的Timer类是中介者模式的一个应用:
// Timer作为中介者协调多个TimerTask对象
public class TimerMediatorExample {
public static void main(String[] args) {
Timer timer = new Timer();
// 创建任务
TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println("任务1执行: " + new Date());
}
};
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println("任务2执行: " + new Date());
}
};
// Timer作为中介者调度任务
timer.scheduleAtFixedRate(task1, 0, 2000); // 每2秒执行一次
timer.scheduleAtFixedRate(task2, 1000, 3000); // 每3秒执行一次,延迟1秒开始
// 运行5秒后取消所有任务
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
}
}
2. MVC框架中的控制器
MVC架构中的控制器(Controller)扮演了中介者的角色:
// 中介者接口
interface UIControlMediator {
void notify(UIComponent component, String event);
}
// 同事类抽象类
abstract class UIComponent {
protected UIControlMediator mediator;
public UIComponent(UIControlMediator mediator) {
this.mediator = mediator;
}
}
// 具体同事类 - 文本框
class TextBox extends UIComponent {
private String text = "";
public TextBox(UIControlMediator mediator) {
super(mediator);
}
public void setText(String text) {
this.text = text;
// 通知中介者
mediator.notify(this, "textChanged");
}
public String getText() {
return text;
}
}
// 具体同事类 - 按钮
class Button extends UIComponent {
private String label;
private boolean enabled = true;
public Button(UIControlMediator mediator, String label) {
super(mediator);
this.label = label;
}
public void click() {
if (enabled) {
System.out.println("按钮 '" + label + "' 被点击");
mediator.notify(this, "clicked");
}
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
// 具体同事类 - 标签
class Label extends UIComponent {
private String text = "";
public Label(UIControlMediator mediator) {
super(mediator);
}
public void setText(String text) {
this.text = text;
System.out.println("标签更新为: " + text);
}
public String getText() {
return text;
}
}
// 具体中介者
class DialogMediator implements UIControlMediator {
private TextBox usernameTextBox;
private TextBox passwordTextBox;
private Button loginButton;
private Button resetButton;
private Label statusLabel;
public DialogMediator(TextBox username, TextBox password,
Button login, Button reset, Label status) {
this.usernameTextBox = username;
this.passwordTextBox = password;
this.loginButton = login;
this.resetButton = reset;
this.statusLabel = status;
}
@Override
public void notify(UIComponent component, String event) {
if (component == usernameTextBox && "textChanged".equals(event)) {
checkLoginEnable();
} else if (component == passwordTextBox && "textChanged".equals(event)) {
checkLoginEnable();
} else if (component == loginButton && "clicked".equals(event)) {
performLogin();
} else if (component == resetButton && "clicked".equals(event)) {
resetForm();
}
}
private void checkLoginEnable() {
String username = usernameTextBox.getText();
String password = passwordTextBox.getText();
loginButton.setEnabled(username.length() > 0 && password.length() > 0);
}
private void performLogin() {
String username = usernameTextBox.getText();
String password = passwordTextBox.getText();
statusLabel.setText("正在登录 " + username + "...");
// 模拟登录过程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
statusLabel.setText("登录成功!");
}
private void resetForm() {
usernameTextBox.setText("");
passwordTextBox.setText("");
statusLabel.setText("表单已重置");
}
}
// 使用示例
public class MVCMediatorDemo {
public static void main(String[] args) {
// 创建UI组件
TextBox usernameTextBox = new TextBox(null);
TextBox passwordTextBox = new TextBox(null);
Button loginButton = new Button(null, "登录");
Button resetButton = new Button(null, "重置");
Label statusLabel = new Label(null);
// 创建中介者
DialogMediator mediator = new DialogMediator(
usernameTextBox, passwordTextBox,
loginButton, resetButton, statusLabel);
// 设置组件的中介者
usernameTextBox = new TextBox(mediator);
passwordTextBox = new TextBox(mediator);
loginButton = new Button(mediator, "登录");
resetButton = new Button(mediator, "重置");
statusLabel = new Label(mediator);
// 模拟用户交互
System.out.println("=== 用户开始输入 ===");
usernameTextBox.setText("admin");
passwordTextBox.setText("123456");
System.out.println("\n=== 用户点击登录 ===");
loginButton.click();
System.out.println("\n=== 用户点击重置 ===");
resetButton.click();
}
}
应用场景
- 系统中对象之间存在复杂的引用关系,导致依赖关系混乱且难以理解
- 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类
- 多个类相互耦合,形成了网状结构
- 聊天室系统:用户通过聊天室进行消息交互
- MVC架构:控制器作为视图和模型的中介者
- GUI组件交互:多个组件之间的协调工作
- 机场管制系统:塔台作为飞机之间的中介者
优缺点
优点
- 降低复杂性:将一对多转换为一对一,降低系统复杂性
- 减少子类生成:避免了大量子类的生成,简化了对象之间的交互
- 降低类间耦合:各个同事类之间解耦,它们只与中介者通信
- 符合迪米特法则:各个同事类之间解耦,符合最少知道原则
缺点
- 中介者类复杂:中介者类可能变得非常复杂,难以维护
- 系统性能受影响:中介者类可能成为系统性能的瓶颈
- 不符合开闭原则:增加新的同事类时可能需要修改中介者类