中介者模式
大约 11 分钟
中介者模式
什么是中介者模式
中介者模式(Mediator Pattern)是一种行为型设计模式,它定义一个中介对象来封装一系列对象之间的交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
中介者模式的核心思想是:
- 用一个中介对象来封装一系列对象之间的交互
- 使对象之间不需要显式地相互引用
- 降低对象之间的耦合度
- 集中控制对象间的复杂交互
为什么需要中介者模式
在实际开发中,当多个对象之间存在复杂的交互关系时,如果让这些对象直接相互引用,会导致系统结构复杂、难以维护和扩展。随着对象数量的增加,对象间的依赖关系会呈指数级增长,形成"网状结构"。中介者模式通过引入中介者对象,将网状结构简化为星型结构,使得系统更加清晰和易于管理。
中介者模式的结构
中介者模式包含以下几个角色:
- 中介者(Mediator):定义一个接口用于与各同事对象通信
- 具体中介者(ConcreteMediator):实现中介者接口,协调各个同事对象的交互
- 同事类(Colleague):每个同事类都知道中介者对象,通过中介者与其他同事通信
- 具体同事类(ConcreteColleague):实现自己的业务逻辑,并通过中介者与其他同事通信
中介者模式的实现
基本实现
// 抽象中介者
abstract class Mediator {
public abstract void sendMessage(String message, Colleague colleague);
}
// 抽象同事类
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
}
// 具体中介者
class ConcreteMediator extends Mediator {
private ConcreteColleagueA colleagueA;
private ConcreteColleagueB colleagueB;
public void setColleagueA(ConcreteColleagueA colleagueA) {
this.colleagueA = colleagueA;
}
public void setColleagueB(ConcreteColleagueB colleagueB) {
this.colleagueB = colleagueB;
}
@Override
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleagueA) {
colleagueB.receiveMessage(message);
} else if (colleague == colleagueB) {
colleagueA.receiveMessage(message);
}
}
}
// 具体同事类A
class ConcreteColleagueA extends Colleague {
public ConcreteColleagueA(Mediator mediator) {
super(mediator);
}
public void send(String message) {
System.out.println("同事A发送消息: " + message);
mediator.sendMessage(message, this);
}
public void receiveMessage(String message) {
System.out.println("同事A收到消息: " + message);
}
}
// 具体同事类B
class ConcreteColleagueB extends Colleague {
public ConcreteColleagueB(Mediator mediator) {
super(mediator);
}
public void send(String message) {
System.out.println("同事B发送消息: " + message);
mediator.sendMessage(message, this);
}
public void receiveMessage(String message) {
System.out.println("同事B收到消息: " + message);
}
}
// 使用示例
public class MediatorDemo {
public static void main(String[] args) {
// 创建中介者
ConcreteMediator mediator = new ConcreteMediator();
// 创建同事对象
ConcreteColleagueA colleagueA = new ConcreteColleagueA(mediator);
ConcreteColleagueB colleagueB = new ConcreteColleagueB(mediator);
// 设置中介者中的同事对象
mediator.setColleagueA(colleagueA);
mediator.setColleagueB(colleagueB);
// 测试通信
System.out.println("=== 中介者模式通信测试 ===");
colleagueA.send("你好,我是同事A");
colleagueB.send("你好,我是同事B");
}
}
聊天室示例
// 聊天室中介者接口
interface ChatRoomMediator {
void sendMessage(String message, User user);
void addUser(User user);
}
// 用户抽象类
abstract class User {
protected ChatRoomMediator mediator;
protected String name;
public User(ChatRoomMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message);
public String getName() {
return name;
}
}
// 聊天室具体中介者
class ChatRoom implements ChatRoomMediator {
private List<User> users = new ArrayList<>();
@Override
public void sendMessage(String message, User user) {
System.out.println(new Date().toString() + " [" + user.getName() + "]: " + message);
// 将消息发送给所有其他用户
for (User u : users) {
if (u != user) {
u.receive(message);
}
}
}
@Override
public void addUser(User user) {
users.add(user);
}
}
// 具体用户类
class ChatUser extends User {
public ChatUser(ChatRoomMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(this.name + " 发送消息:");
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(this.name + " 收到消息: " + message);
}
}
// 使用示例
public class ChatRoomDemo {
public static void main(String[] args) throws InterruptedException {
// 创建聊天室中介者
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);
// 测试聊天
System.out.println("=== 聊天室测试 ===");
user1.send("大家好!");
Thread.sleep(1000); // 模拟时间间隔
user2.send("你好,张三!");
Thread.sleep(1000);
user3.send("欢迎加入聊天室!");
}
}
中介者模式的应用场景
- GUI组件交互:多个界面组件之间的协调交互
- 聊天系统:聊天室中用户之间的消息传递
- 机场管制系统:飞机与塔台之间的通信
- MVC架构:Controller作为View和Model之间的中介者
- 工作流系统:不同步骤之间的协调
- 事件处理系统:事件发布者和订阅者之间的协调
中介者模式的优缺点
优点
- 降低复杂性:将一对多的依赖关系简化为一对一的依赖关系
- 降低耦合度:对象之间不需要直接相互引用
- 集中控制:将对象间的交互集中到中介者中统一管理
- 易于维护:各个对象可以独立变化,不会影响其他对象
缺点
- 中介者复杂化:中介者可能变得非常复杂,难以维护
- 违反单一职责原则:中介者可能承担过多的职责
- 增加系统复杂度:对于简单的交互,使用中介者模式可能显得过于复杂
中介者模式与其他模式的比较
与观察者模式的区别
- 中介者模式:集中控制多个对象之间的交互
- 观察者模式:一对多的依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知
与外观模式的区别
- 中介者模式:协调多个对象之间的复杂交互
- 外观模式:为复杂的子系统提供一个简单的接口
与命令模式的区别
- 中介者模式:关注对象间的交互协调
- 命令模式:关注将请求封装成对象
实际项目中的应用
// GUI组件交互示例
// GUI中介者接口
interface GUIMediator {
void componentChanged(Component component);
}
// 组件抽象类
abstract class Component {
protected GUIMediator mediator;
public Component(GUIMediator mediator) {
this.mediator = mediator;
}
public abstract void update();
public abstract void changed();
}
// 按钮组件
class Button extends Component {
private String name;
private boolean enabled = true;
public Button(GUIMediator mediator, String name) {
super(mediator);
this.name = name;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
update();
}
public boolean isEnabled() {
return enabled;
}
public void click() {
if (enabled) {
System.out.println("点击按钮: " + name);
changed();
} else {
System.out.println("按钮 " + name + " 不可用");
}
}
@Override
public void update() {
System.out.println("更新按钮 " + name + " 状态: " + (enabled ? "启用" : "禁用"));
}
@Override
public void changed() {
mediator.componentChanged(this);
}
}
// 文本框组件
class TextBox extends Component {
private String name;
private String text = "";
public TextBox(GUIMediator mediator, String name) {
super(mediator);
this.name = name;
}
public void setText(String text) {
this.text = text;
System.out.println("设置文本框 " + name + " 内容: " + text);
changed();
}
public String getText() {
return text;
}
@Override
public void update() {
System.out.println("更新文本框 " + name);
}
@Override
public void changed() {
mediator.componentChanged(this);
}
}
// 标签组件
class Label extends Component {
private String name;
private String text = "";
public Label(GUIMediator mediator, String name) {
super(mediator);
this.name = name;
}
public void setText(String text) {
this.text = text;
System.out.println("设置标签 " + name + " 内容: " + text);
}
public String getText() {
return text;
}
@Override
public void update() {
System.out.println("更新标签 " + name + " 内容: " + text);
}
@Override
public void changed() {
mediator.componentChanged(this);
}
}
// 下拉框组件
class ComboBox extends Component {
private String name;
private List<String> items = new ArrayList<>();
private String selectedItem;
public ComboBox(GUIMediator mediator, String name) {
super(mediator);
this.name = name;
}
public void addItem(String item) {
items.add(item);
}
public void selectItem(String item) {
if (items.contains(item)) {
this.selectedItem = item;
System.out.println("下拉框 " + name + " 选择项: " + item);
changed();
}
}
public String getSelectedItem() {
return selectedItem;
}
@Override
public void update() {
System.out.println("更新下拉框 " + name);
}
@Override
public void changed() {
mediator.componentChanged(this);
}
}
// 登录窗口中介者
class LoginMediator implements GUIMediator {
private Button loginButton;
private Button cancelButton;
private TextBox usernameTextBox;
private TextBox passwordTextBox;
private Label messageLabel;
private ComboBox userTypeComboBox;
public void setLoginButton(Button loginButton) {
this.loginButton = loginButton;
}
public void setCancelButton(Button cancelButton) {
this.cancelButton = cancelButton;
}
public void setUsernameTextBox(TextBox usernameTextBox) {
this.usernameTextBox = usernameTextBox;
}
public void setPasswordTextBox(TextBox passwordTextBox) {
this.passwordTextBox = passwordTextBox;
}
public void setMessageLabel(Label messageLabel) {
this.messageLabel = messageLabel;
}
public void setUserTypeComboBox(ComboBox userTypeComboBox) {
this.userTypeComboBox = userTypeComboBox;
}
@Override
public void componentChanged(Component component) {
// 根据组件变化调整其他组件状态
if (component == usernameTextBox || component == passwordTextBox || component == userTypeComboBox) {
// 检查用户名和密码是否为空
String username = usernameTextBox.getText();
String password = passwordTextBox.getText();
String userType = userTypeComboBox.getSelectedItem();
if (username != null && !username.isEmpty() &&
password != null && !password.isEmpty() &&
userType != null && !userType.isEmpty()) {
loginButton.setEnabled(true);
messageLabel.setText("请输入用户名和密码");
} else {
loginButton.setEnabled(false);
if (username == null || username.isEmpty()) {
messageLabel.setText("请输入用户名");
} else if (password == null || password.isEmpty()) {
messageLabel.setText("请输入密码");
} else {
messageLabel.setText("请选择用户类型");
}
}
} else if (component == loginButton) {
// 处理登录按钮点击
String username = usernameTextBox.getText();
String password = passwordTextBox.getText();
String userType = userTypeComboBox.getSelectedItem();
if ("admin".equals(username) && "123456".equals(password) && "管理员".equals(userType)) {
messageLabel.setText("管理员登录成功");
} else if ("user".equals(username) && "123456".equals(password) && "普通用户".equals(userType)) {
messageLabel.setText("普通用户登录成功");
} else {
messageLabel.setText("用户名或密码错误");
}
} else if (component == cancelButton) {
// 处理取消按钮点击
usernameTextBox.setText("");
passwordTextBox.setText("");
userTypeComboBox.selectItem("");
messageLabel.setText("已取消登录");
}
}
}
// 使用示例
public class GUILoginDemo {
public static void main(String[] args) {
// 创建中介者
LoginMediator mediator = new LoginMediator();
// 创建组件
Button loginButton = new Button(mediator, "登录");
Button cancelButton = new Button(mediator, "取消");
TextBox usernameTextBox = new TextBox(mediator, "用户名");
TextBox passwordTextBox = new TextBox(mediator, "密码");
Label messageLabel = new Label(mediator, "消息");
ComboBox userTypeComboBox = new ComboBox(mediator, "用户类型");
// 设置下拉框选项
userTypeComboBox.addItem("管理员");
userTypeComboBox.addItem("普通用户");
// 设置中介者中的组件
mediator.setLoginButton(loginButton);
mediator.setCancelButton(cancelButton);
mediator.setUsernameTextBox(usernameTextBox);
mediator.setPasswordTextBox(passwordTextBox);
mediator.setMessageLabel(messageLabel);
mediator.setUserTypeComboBox(userTypeComboBox);
// 初始化按钮状态
loginButton.setEnabled(false);
messageLabel.setText("请输入用户名和密码");
// 模拟用户操作
System.out.println("=== GUI登录界面测试 ===");
// 输入用户名
System.out.println("\n1. 输入用户名:");
usernameTextBox.setText("admin");
// 输入密码
System.out.println("\n2. 输入密码:");
passwordTextBox.setText("123456");
// 选择用户类型
System.out.println("\n3. 选择用户类型:");
userTypeComboBox.selectItem("管理员");
// 点击登录按钮
System.out.println("\n4. 点击登录按钮:");
loginButton.click();
// 点击取消按钮
System.out.println("\n5. 点击取消按钮:");
cancelButton.click();
}
}
// 机场管制系统示例
// 飞机类
class Aircraft {
private String callSign;
private int altitude;
private AirTrafficControlMediator atc;
public Aircraft(String callSign, AirTrafficControlMediator atc) {
this.callSign = callSign;
this.atc = atc;
this.atc.registerAircraft(this);
}
public void climb(int feet) {
System.out.println(callSign + " 请求爬升 " + feet + " 英尺");
atc.requestClimb(this, feet);
}
public void descend(int feet) {
System.out.println(callSign + " 请求下降 " + feet + " 英尺");
atc.requestDescend(this, feet);
}
public void receiveMessage(String message) {
System.out.println(callSign + " 收到管制指令: " + message);
}
public String getCallSign() {
return callSign;
}
public int getAltitude() {
return altitude;
}
public void setAltitude(int altitude) {
this.altitude = altitude;
}
}
// 空中交通管制中介者接口
interface AirTrafficControlMediator {
void registerAircraft(Aircraft aircraft);
void requestClimb(Aircraft aircraft, int feet);
void requestDescend(Aircraft aircraft, int feet);
}
// 空中交通管制塔台
class AirTrafficControlTower implements AirTrafficControlMediator {
private List<Aircraft> aircrafts = new ArrayList<>();
private Map<Aircraft, Integer> altitudes = new HashMap<>();
@Override
public void registerAircraft(Aircraft aircraft) {
aircrafts.add(aircraft);
altitudes.put(aircraft, 0);
System.out.println("管制塔台注册飞机: " + aircraft.getCallSign());
}
@Override
public void requestClimb(Aircraft aircraft, int feet) {
int currentAltitude = altitudes.get(aircraft);
int newAltitude = currentAltitude + feet;
// 检查是否有冲突
boolean conflict = false;
for (Aircraft other : aircrafts) {
if (other != aircraft) {
int otherAltitude = altitudes.get(other);
if (Math.abs(newAltitude - otherAltitude) < 1000) {
conflict = true;
break;
}
}
}
if (!conflict) {
altitudes.put(aircraft, newAltitude);
aircraft.receiveMessage("批准爬升到 " + newAltitude + " 英尺");
} else {
aircraft.receiveMessage("拒绝爬升请求,存在飞行冲突");
}
}
@Override
public void requestDescend(Aircraft aircraft, int feet) {
int currentAltitude = altitudes.get(aircraft);
int newAltitude = currentAltitude - feet;
// 检查是否有冲突
boolean conflict = false;
for (Aircraft other : aircrafts) {
if (other != aircraft) {
int otherAltitude = altitudes.get(other);
if (Math.abs(newAltitude - otherAltitude) < 1000) {
conflict = true;
break;
}
}
}
if (!conflict && newAltitude >= 0) {
altitudes.put(aircraft, newAltitude);
aircraft.receiveMessage("批准下降到 " + newAltitude + " 英尺");
} else if (newAltitude < 0) {
aircraft.receiveMessage("拒绝下降请求,高度不能低于地面");
} else {
aircraft.receiveMessage("拒绝下降请求,存在飞行冲突");
}
}
}
// 使用示例
public class AirTrafficControlDemo {
public static void main(String[] args) {
// 创建空中交通管制塔台
AirTrafficControlTower atc = new AirTrafficControlTower();
// 创建飞机
Aircraft aircraft1 = new Aircraft("CA123", atc);
Aircraft aircraft2 = new Aircraft("CZ456", atc);
Aircraft aircraft3 = new Aircraft("MU789", atc);
// 设置初始高度
// 这里简化处理,实际应该通过中介者设置
try {
java.lang.reflect.Field altitudeField = Aircraft.class.getDeclaredField("altitude");
altitudeField.setAccessible(true);
altitudeField.set(aircraft1, 10000);
altitudeField.set(aircraft2, 12000);
altitudeField.set(aircraft3, 8000);
} catch (Exception e) {
e.printStackTrace();
}
// 测试飞行操作
System.out.println("=== 空中交通管制测试 ===");
// 飞机1请求爬升
System.out.println("\n1. 飞机1请求爬升:");
aircraft1.climb(3000);
// 飞机2请求下降
System.out.println("\n2. 飞机2请求下降:");
aircraft2.descend(2000);
// 飞机3请求爬升(可能产生冲突)
System.out.println("\n3. 飞机3请求爬升:");
aircraft3.climb(5000);
// 飞机1再次请求爬升
System.out.println("\n4. 飞机1再次请求爬升:");
aircraft1.climb(1000);
}
}
Java中的中介者模式应用
// Swing中的中介者模式示例
// 在Swing中,Frame、Dialog等容器类充当了中介者的角色
// 各个组件通过容器进行协调和通信
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SwingMediatorDemo extends JFrame {
private JButton button1;
private JButton button2;
private JTextField textField;
private JLabel label;
public SwingMediatorDemo() {
setTitle("Swing中介者模式示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
setLayout(new FlowLayout());
// 创建组件
button1 = new JButton("按钮1");
button2 = new JButton("按钮2");
textField = new JTextField(15);
label = new JLabel("状态信息");
// 添加组件到窗口(窗口作为中介者协调组件)
add(button1);
add(button2);
add(textField);
add(label);
// 添加事件监听器
button1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textField.setText("按钮1被点击");
label.setText("执行了按钮1的操作");
}
});
button2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
textField.setText("按钮2被点击");
label.setText("执行了按钮2的操作");
}
});
textField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("输入了文本: " + textField.getText());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingMediatorDemo().setVisible(true);
}
});
}
}
总结
中介者模式是一种非常实用的行为型设计模式,它通过引入中介者对象来封装对象之间的复杂交互,从而降低系统的耦合度,简化对象之间的依赖关系。在实际开发中,当我们面临多个对象之间存在复杂交互关系时,中介者模式是一个很好的解决方案。
使用中介者模式的关键点:
- 识别需要协调交互的多个对象
- 定义中介者接口
- 实现具体中介者类,协调各个对象的交互
- 在同事类中维护对中介者的引用
- 通过中介者进行对象间的通信
中介者模式的优点是能够降低系统复杂性,减少对象间的耦合度,便于维护和扩展。但需要注意的是,中介者本身可能变得复杂,需要合理设计以避免中介者成为系统的瓶颈。在现代Java开发中,中介者模式广泛应用于GUI系统、聊天系统、工作流系统等需要协调多个对象交互的场景。