化繁为简:中介者模式如何管理复杂对象交互
中介者模式 是一种行为型设计模式,定义了一个中介者对象,来封装一组对象之间的交互。中介者模式通过将对象之间的交互行为从多个对象中抽离出来,集中封装在一个中介者对象中,从而使各个对象之间的耦合松散,且可以独立地改变它们之间的交互。
核心思想:
中介者模式通过引入一个中介者,协调多个对象之间的交互,避免对象之间的直接通信 ,从而减少对象之间的耦合。
中介者模式的组成角色
Mediator(中介者接口):
- 中介者定义了对象之间交互的接口,负责协调各个对象之间的通信行为。
ConcreteMediator(具体中介者):
- 实现了
Mediator
接口,协调各具体同事对象之间的交互。它了解所有的同事对象,并通过其实现交互逻辑。
Colleague(同事类):
- 每个同事对象只知道中介者,不能直接与其他同事对象通信。所有的交互都通过中介者来完成。
ConcreteColleague(具体同事类):
- 实现了
Colleague
接口,依赖中介者与其他同事对象通信。每个具体同事对象的行为受到中介者的约束。
中介者模式的 UML 类图
类图解释:
- Mediator(中介者接口) :定义了同事对象之间的通信接口,通常定义
send()
方法来协调通信。 - ConcreteMediator(具体中介者) :
- 实现了
Mediator
接口,具体负责管理和协调同事对象之间的通信。它知道所有的具体同事对象,并通过send()
方法传递消息或协调操作。 - 它也可以持有具体的同事对象的引用,负责管理这些对象。
- 实现了
- Colleague(同事类):抽象类或接口,每个同事对象依赖中介者与其他同事进行交互。它不直接与其他同事对象通信,而是通过中介者通信。
- ConcreteColleague1、ConcreteColleague2(具体同事类) :实现
Colleague
,定义各自的具体操作。同事对象通过中介者协调相互间的通信
工作原理
- 集中通信 :中介者模式通过引入
Mediator
,将多个对象之间的交互逻辑集中到中介者中,使得各个同事类之间的关系变得松散耦合。 - 消息传递 :同事对象通过调用中介者的
send()
方法进行通信。中介者负责接收和转发消息,并协调其他同事对象的行为。 - 解耦同事对象:同事对象之间不直接交互,而是通过中介者来处理。这样一来,各个对象之间的依赖关系被削弱了。
案例:机场塔台与飞机的调度
场景说明:
在机场,飞机起飞和降落的调度是一个非常复杂的过程。如果每架飞机都直接与其他飞机进行通信,会导致混乱并增加空中事故的风险。因此,机场有一个控制塔(塔台) ,它负责协调所有飞机的起飞和降落。
控制塔是中介者,飞机之间的所有通信都必须通过控制塔进行。飞机通过塔台来获取是否可以起飞或降落,从而避免与其他飞机发生冲突。
中介者模式的角色在机场塔台场景中的映射:
- Mediator(中介者接口):机场控制塔,负责协调所有飞机的起飞和降落。
- ConcreteMediator(具体中介者):具体实现的控制塔,协调飞机的飞行状态。
- Colleague(同事类):抽象飞机类,代表参与通信的对象(飞机)。
- ConcreteColleague(具体同事类):具体的飞机类,通过控制塔来决定起飞或降落。
代码实现:机场塔台调度系统
Step 1: 定义中介者接口
中介者接口定义了调度方法,用于协调飞机之间的通信。
java
// 中介者接口:塔台
public interface Mediator {
void notify(String message, Airplane airplane);
}
Step 2: 实现具体的中介者
ControlTower
类是具体的中介者,它负责接收飞机的状态并通知其他飞机,确保起飞和降落顺序的安全。
java
import java.util.ArrayList;
import java.util.List;
// 具体中介者:控制塔
public class ControlTower implements Mediator {
private List<Airplane> airplanes;
public ControlTower() {
this.airplanes = new ArrayList<>();
}
public void registerAirplane(Airplane airplane) {
airplanes.add(airplane);
}
@Override
public void notify(String message, Airplane airplane) {
for (Airplane a : airplanes) {
if (a != airplane) {
a.receive(message); // 通知其他飞机
}
}
}
}
Step 3: 定义飞机抽象类
飞机类通过中介者来发送和接收信息,而不直接与其他飞机通信。
java
// 飞机抽象类
public abstract class Airplane {
protected Mediator mediator;
protected String name;
public Airplane(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message);
}
Step 4: 实现具体飞机类
具体飞机类实现了 send()
和 receive()
方法,通过塔台来发送和接收消息。
Boeing737 类
java
// 具体飞机:Boeing 737
public class Boeing737 extends Airplane {
public Boeing737(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(this.name + " sends message: " + message);
mediator.notify(message, this); // 通过塔台发送消息
}
@Override
public void receive(String message) {
System.out.println(this.name + " receives message: " + message);
}
}
AirbusA320 类
java
// 具体飞机:Airbus A320
public class AirbusA320 extends Airplane {
public AirbusA320(Mediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(this.name + " sends message: " + message);
mediator.notify(message, this); // 通过塔台发送消息
}
@Override
public void receive(String message) {
System.out.println(this.name + " receives message: " + message);
}
}
Step 5: 测试中介者模式
通过 ControlTower
来协调 Boeing737
和 AirbusA320
之间的通信,确保飞机的起飞和降落顺序。
java
public class MediatorPatternDemo {
public static void main(String[] args) {
// 创建控制塔
ControlTower tower = new ControlTower();
// 创建飞机并注册到塔台
Airplane boeing737 = new Boeing737(tower, "Boeing 737");
Airplane airbusA320 = new AirbusA320(tower, "Airbus A320");
tower.registerAirplane(boeing737);
tower.registerAirplane(airbusA320);
// 飞机发送消息
boeing737.send("Requesting permission to land.");
airbusA320.send("Requesting permission to take off.");
}
}
输出结果:
Boeing 737 sends message: Requesting permission to land.
Airbus A320 receives message: Requesting permission to land.
Airbus A320 sends message: Requesting permission to take off.
Boeing 737 receives message: Requesting permission to take off.
中介者模式在机场塔台场景中的工作原理
- 集中通信:所有的飞机(同事类)不直接通信,而是通过控制塔(中介者)进行协调。每架飞机都通过塔台发送和接收消息。
- 消息传递:当一架飞机发送起飞或降落请求时,塔台负责通知其他飞机,并保证飞行安全和秩序。
- 降低耦合性:飞机之间不直接通信,所有交互通过塔台完成,从而降低了飞机之间的耦合,增强了系统的灵活性和扩展性。
SpringMVC 中的 应用
在 Spring Framework 中,DispatcherServlet
作为前端控制器,实际上也承担了类似于中介者的作用。它在 Spring MVC 架构中负责协调不同组件(如控制器、视图解析器和处理器)的交互。
原理:
DispatcherServlet
作为一个统一的请求分发器,负责接收 HTTP 请求,并根据请求的 URL 或其他条件,将请求分发给适当的处理器(如@Controller
的方法)。它并不直接参与具体的请求处理,而是协调多个组件来完成请求-响应的流程。- 控制器、视图解析器、处理器等组件之间不直接通信,而是通过
DispatcherServlet
进行交互。
java
// DispatcherServlet 伪代码,简化示例
public class DispatcherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 根据请求查找对应的控制器
Handler handler = getHandler(request);
// 调用控制器处理请求
ModelAndView mv = handler.handleRequest(request, response);
// 解析视图并返回响应
render(mv, response);
}
}
在这里,DispatcherServlet
类似于中介者,协调多个组件之间的交互,不同的控制器和视图解析器不直接互相通信,而是通过 DispatcherServlet
进行处理。
中介者模式的优缺点与应用场景总结
优点:
- 降低对象之间的耦合性 :
- 中介者模式通过引入中介者,使多个对象之间的依赖关系转变为与中介者的依赖,减少了对象之间的直接交互,降低了系统的耦合度。
- 简化对象之间的通信 :
- 所有通信都通过中介者集中管理,使得系统结构更加清晰,逻辑集中,尤其在多方通信的复杂系统中,简化了交互逻辑。
- 符合开闭原则 :
- 中介者模式可以方便地扩展或修改交互逻辑,而不影响各个同事对象。可以通过修改中介者来增加或调整各对象之间的交互。
- 提高系统的灵活性 :
- 当需要增加新的对象或修改对象之间的交互行为时,可以通过中介者进行控制,增强了系统的扩展性和灵活性。
缺点:
- 中介者可能变得复杂 :
- 随着系统中同事对象的增多,中介者需要处理的交互逻辑也会变得越来越复杂,可能导致中介者变得难以维护,形成一个"上帝对象"。
- 不适合简单场景 :
- 如果对象之间的交互非常简单,使用中介者模式会引入不必要的复杂性,增加维护成本。
应用场景:
- 复杂对象交互的系统 :
- 在多个对象之间存在复杂交互的系统中,中介者模式非常适用。例如,GUI 控件交互(如按钮、文本框、下拉菜单等)可以通过中介者来管理。
- 消息队列系统 :
- 在消息队列(如 JMS)中,中介者管理生产者和消费者之间的消息传递,解耦了消息的发送和接收,避免直接通信。
- 事件驱动系统 :
- 在事件驱动架构中,事件发布者和监听者之间的通信可以通过中介者来协调,避免对象之间的紧密耦合。例如,Spring 的事件驱动机制 利用
ApplicationEventPublisher
和ApplicationListener
解耦了事件发布和处理。
- 在事件驱动架构中,事件发布者和监听者之间的通信可以通过中介者来协调,避免对象之间的紧密耦合。例如,Spring 的事件驱动机制 利用
- 航空管制系统 :
- 像机场塔台这种需要协调多架飞机起降的系统,中介者可以集中管理对象的行为,保证复杂交互的有序进行。