中介者模式详解
- 定义核心
中介者模式属于行为型设计模式 。其核心是引入一个中介者对象,它负责封装一系列对象之间的交互逻辑。原本对象之间可能存在复杂的直接引用和交互,通过中介者,这些对象只需要与中介者交互,降低了对象之间的耦合度。 - 结构图元素分析
- Mediator(中介者接口):定义了中介者对象与各个同事对象交互的接口规范,规定了中介者应该具备哪些方法来处理同事对象的请求等操作。
- ConcreteMediator(具体中介者):实现了Mediator接口,具体负责协调各个同事对象之间的交互。它持有具体同事对象的引用,根据业务逻辑来决定如何转发和处理同事对象的操作。
- Colleague(同事接口):定义了同事对象的基本行为规范,所有具体同事类都实现这个接口。同事对象只知道中介者,通过中介者来与其他同事对象交互。
- ConcreteColleague1、ConcreteColleague2(具体同事类):实现了Colleague接口,代表系统中具体需要交互的对象。它们通过中介者来发送和接收消息,完成业务功能 。
- 应用场景举例
比如在一个图形界面系统中,有按钮、文本框、下拉框等多个组件。这些组件之间可能存在联动关系,如点击某个按钮后,文本框内容要更新,下拉框状态要改变。如果各个组件直接相互引用并处理交互逻辑,代码会变得混乱且难以维护。使用中介者模式,可创建一个中介者类,各个组件(同事对象)只与中介者交互,中介者负责协调这些组件之间的联动逻辑 ,使系统结构更清晰,可维护性增强。
这张图片介绍了中介者模式(Mediator Pattern),这是软件设计模式中的一种行为模式。中介者模式的核心思想是通过一个中介对象来封装一系列对象之间的交互,使得这些对象不需要直接相互引用,从而降低它们的耦合度,并可以独立地改变它们之间的交互方式。
图片中包含以下内容:
- 标题:中介者模式。
- 解释:中介者模式使用一个中介对象来封装对象之间的交互。这样,对象之间不需要直接引用,从而使得它们的耦合度降低,并且可以独立地改变它们之间的交互。
- 结构图:
- Mediator:中介者接口,定义了与同事对象交互的方法。
- ConcreteMediator:具体的中介者类,实现了中介者接口,负责协调具体的同事对象之间的交互。
- Colleague:同事接口,定义了与其他同事对象交互的方法。
- ConcreteColleague1 和 ConcreteColleague2:具体的同事类,实现了同事接口,通过中介者进行交互。
结构图中展示了中介者模式的基本组成和对象之间的关系。具体的中介者类(ConcreteMediator)通过同事接口(Colleague)与具体的同事类(ConcreteColleague1 和 ConcreteColleague2)进行交互,从而实现对象之间的解耦和灵活的交互方式。
以下是使用Java语言,通过中介者模式实现一个简单计算器的示例代码:
定义中介者接口
public interface CalculatorMediator {
void calculate(String operator, int num1, int num2);
}
实现具体中介者
public class ConcreteCalculatorMediator implements CalculatorMediator {
private Display display;
private Button button;
public ConcreteCalculatorMediator(Display display, Button button) {
this.display = display;
this.button = button;
}
@Override
public void calculate(String operator, int num1, int num2) {
int result;
if ("+".equals(operator)) {
result = num1 + num2;
} else if ("-".equals(operator)) {
result = num1 - num2;
} else if ("*".equals(operator)) {
result = num1 * num2;
} else if ("/".equals(operator)) {
result = num1 / num2;
} else {
throw new IllegalArgumentException("不支持的操作符");
}
display.showResult(result);
}
}
定义同事类(显示部分)
public class Display {
private CalculatorMediator mediator;
public Display(CalculatorMediator mediator) {
this.mediator = mediator;
}
public void showResult(int result) {
System.out.println("计算结果为: " + result);
}
}
定义同事类(按钮部分,模拟用户输入操作)
public class Button {
private CalculatorMediator mediator;
public Button(CalculatorMediator mediator) {
this.mediator = mediator;
}
public void click(String operator, int num1, int num2) {
mediator.calculate(operator, num1, num2);
}
}
测试代码
public class CalculatorTest {
public static void main(String[] args) {
Display display = new Display(null);
Button button = new Button(null);
CalculatorMediator mediator = new ConcreteCalculatorMediator(display, button);
display = new Display(mediator);
button = new Button(mediator);
button.click("+", 3, 5);
}
}
代码说明
- 中介者接口
CalculatorMediator
:定义了calculate
方法,用于接收操作符和两个操作数并进行计算相关操作。 - 具体中介者
ConcreteCalculatorMediator
:实现了中介者接口,持有Display
和Button
这两个同事类的实例。在calculate
方法中,根据不同的操作符进行相应计算,并调用Display
的方法展示结果。 - 同事类
Display
:负责显示计算结果,通过中介者获取计算结果并展示。 - 同事类
Button
:模拟用户点击按钮操作,将操作符和操作数传递给中介者进行计算。 - 测试代码
CalculatorTest
:创建相关对象并设置中介者关联,模拟按钮点击操作来测试计算器功能。
在其他编程语言(如Python等)中,也可以基于类似的思路,通过定义类和方法来实现中介者模式的简单计算器,核心都是通过中介者来协调不同功能模块(同事对象)之间的交互。
当然可以。中介者模式在软件设计中非常常见,以下是一些实际的例子:
-
聊天室系统:
- 在一个聊天室中,用户(同事对象)不需要直接相互发送消息。相反,他们通过聊天室服务器(中介者对象)发送消息。服务器负责接收消息并将其转发给所有其他用户,从而管理用户之间的通信。
-
事件处理系统:
- 在图形用户界面(GUI)应用程序中,事件处理系统(中介者对象)管理用户界面元素(同事对象)之间的交互。例如,当用户点击一个按钮时,事件处理系统会接收到这个事件,并调用相应的处理函数来响应用户的点击。
-
MVC(模型-视图-控制器)模式:
- 在MVC架构中,控制器(中介者对象)充当模型(数据)和视图(用户界面)之间的中介。控制器接收用户的输入(如点击按钮),更新模型,并通知视图进行相应的更新。
-
网络代理服务器:
- 代理服务器(中介者对象)在客户端(同事对象)和服务器(同事对象)之间进行通信。客户端通过代理服务器发送请求,代理服务器再将请求转发给服务器,并将服务器的响应返回给客户端。
-
支付网关:
- 在电子商务系统中,支付网关(中介者对象)管理客户(同事对象)和银行(同事对象)之间的支付交易。客户通过支付网关提交支付请求,支付网关处理请求并与银行进行交互,最后将交易结果返回给客户。
-
操作系统的进程间通信(IPC):
- 操作系统(中介者对象)提供了进程间通信的机制,如管道、消息队列、共享内存等。进程(同事对象)通过这些机制进行数据交换,而不需要直接相互访问内存空间。
这些例子展示了中介者模式如何在不同的场景中用于解耦对象之间的直接交互,从而提高系统的灵活性和可维护性。
在中介者模式里,具体中介者处于核心地位,其主要功能是对对象间的交互逻辑进行封装,以此降低对象之间的耦合度。下面结合计算器示例,详细剖析具体中介者的作用:
1. 封装交互逻辑
具体中介者把原本分布在各个对象中的交互逻辑集中起来进行管理。在计算器示例中,像加法、减法等运算逻辑原本可能分散在不同组件里,而现在统一由ConcreteCalculatorMediator
的calculate
方法来处理。
public void calculate(String operator, int num1, int num2) {
int result;
if ("+".equals(operator)) {
result = num1 + num2;
} else if ("-".equals(operator)) {
result = num1 - num2;
}
display.showResult(result);
}
通过这种方式,运算逻辑被集中起来,代码的可维护性得到显著提升。
2. 降低耦合度
具体中介者让同事对象之间不再直接进行交互,而是通过中介者来间接沟通。在计算器中:
- Button类:它只需调用中介者的
calculate
方法,无需了解Display
类的具体实现。 - Display类:仅负责展示结果,不用关心计算逻辑。
这样一来,同事对象之间的依赖关系从多对多变成了简单的一对多,系统结构变得更加清晰。
3. 集中控制交互流程
具体中介者对整个交互流程起到了协调作用。在计算器执行加法运算时:
- Button向中介者发送计算请求。
- 中介者进行加法运算。
- 中介者通知Display展示结果。
整个流程由中介者统一把控,同事对象只需遵循中介者的接口规范即可。
4. 持有同事对象引用
具体中介者需要持有所有相关同事对象的引用,以此实现消息的转发。在计算器中:
private Display display;
private Button button;
public ConcreteCalculatorMediator(Display display, Button button) {
this.display = display;
this.button = button;
}
通过这些引用,中介者能够在同事对象之间传递消息。
5. 促进可扩展性
如果要对计算器进行功能扩展,比如增加开方运算,只需对中介者进行修改,而无需改动Button
和Display
类。
// 新增开方运算支持
else if ("sqrt".equals(operator)) {
result = Math.sqrt(num1);
}
这种设计符合开闭原则,即对扩展开放,对修改关闭。
中介者模式与MVC的对比
中介者模式和MVC(Model-View-Controller)模式有相似之处,但也存在明显区别:
- 相似点:两者都强调对交互逻辑进行集中管理。
- 不同点:
- MVC:主要关注数据(Model)、视图(View)和控制器(Controller)之间的分离,适用于构建大型应用程序的整体架构。
- 中介者模式:更侧重于解决对象之间复杂的网状交互问题,是一种具体的设计模式。
在实际应用中,中介者模式常被用于实现GUI组件间的联动、消息队列系统的消息路由等场景。
中介者模式和观察者模式都属于行为型设计模式,用于协调对象间交互,但存在诸多区别:
设计目的
- 中介者模式:旨在封装对象间交互,通过中介者对象协调,避免对象间直接依赖,使对象耦合松散,便于独立改变交互逻辑,适合对象交互复杂的场景,如 GUI 界面中各组件复杂联动 。
- 观察者模式:定义对象间一对多依赖关系,当被观察对象状态改变时,自动通知依赖它的观察者对象,专注于消息传递和数据同步,像天气信息更新推送给多个显示设备 。
交互方式
- 中介者模式:对象间不直接交互,都与中介者通信,交互是多对多的,中介者统一管理控制消息流向和处理逻辑 ,如聊天系统中用户通过服务器(中介者)收发消息。
- 观察者模式:是单向的一对多交互,被观察者状态变化时通知观察者,观察者被动接收通知做出响应,如邮件订阅系统,新邮件发布(被观察者状态改变)通知订阅用户(观察者) 。
依赖关系
- 中介者模式:对象仅依赖中介者,对象间相互解耦,对象无需知道其他对象存在,只和中介者关联 ,比如多个游戏角色通过游戏服务器(中介者)交互,角色间无直接依赖。
- 观察者模式:观察者依赖被观察者状态,被观察者需维护观察者列表,耦合度相对较高,像股票行情软件中,股票数据(被观察者)和股民关注界面(观察者)存在依赖 。
通知机制
- 中介者模式:无固定通知方向,对象可随时向中介者发送请求或消息,中介者按需转发处理,如系统中不同模块向消息中介发送业务请求,中介者协调处理 。
- 观察者模式:被观察者状态改变时主动通知观察者,通常有注册(订阅)和注销(取消订阅)机制管理观察者,如新闻推送应用,用户订阅频道(注册为观察者)后接收新闻更新通知 。
复杂度
- 中介者模式:中介者承担大量协调工作,可能变得复杂庞大,中介者逻辑出错影响多个对象交互;但能有效简化对象间复杂关系。
- 观察者模式:相对简单,主要处理被观察者状态变化通知及观察者响应逻辑,若观察者过多或依赖层次复杂,管理和维护观察者列表会变困难。
-
中介者模式适用场景
- GUI 开发 :图形界面里,按钮、文本框、下拉框等组件间交互频繁。如在一个订单管理界面,点击“提交订单”按钮,可能需更新文本框显示订单状态,同时让下拉框不可用。用中介者模式,中介者能统一管理这些组件交互逻辑,降低耦合,比如 Java 的 Swing 或 JavaFX 开发中就可应用 。
- 系统组件通信 :当系统内多个组件存在复杂交互时适用。像电商系统中,库存模块、订单模块、支付模块间关联紧密。库存变动影响订单状态,订单支付情况又关联库存和支付模块。中介者可协调它们交互,使模块专注自身功能,提升可维护性和扩展性 。
- 多人聊天系统 :在聊天室场景,每个用户发送消息,原本需向其他所有用户直接发送,若用户众多会很复杂。引入中介者(服务器),用户只需将消息发给中介者,由中介者负责转发给其他用户,简化通信流程 。
- 游戏开发 :游戏中角色、道具、场景等对象交互复杂。例如角色拾取道具,可能触发场景变化或角色属性改变。通过中介者模式,中介者可管理这些交互逻辑,降低各对象间耦合,方便修改和扩展游戏功能 。
观察者模式适用场景
- 事件监听系统 :如网页开发中,按钮点击、鼠标移动、键盘输入等事件。以按钮点击为例,可将按钮视为被观察者,点击事件监听器作为观察者。按钮状态改变(被点击)时,自动通知相关监听器执行对应操作,像提交表单、跳转页面等 。
- 消息订阅 - 发布系统 :在邮件订阅、新闻推送等场景中,发布者(如新闻网站、邮件服务器)是被观察者,订阅用户是观察者。当有新内容发布(被观察者状态改变),订阅用户能及时收到通知获取信息 。
- 数据变化通知 :在数据库应用里,若多个模块依赖某些数据。当数据更新(被观察数据状态改变),依赖该数据的模块(观察者)需被通知并更新。如电商系统商品库存数据变化,需通知前端展示模块、订单模块等做出响应 。
- 软件系统状态监控 :在操作系统或大型软件中,监控系统资源状态(如 CPU 使用率、内存占用)。将资源状态视为被观察对象,监控模块作为观察者。资源状态变化超出阈值时,通知监控模块处理,如发出警报、自动调整资源分配 。