文章目录
- 1 基本介绍
- 2 案例
- 2.1 Developer 抽象类
- 2.2 FrontendDeveloper 类
- 2.3 BackendDeveloper 类
- 2.4 Mediator 接口
- 2.5 ProjectManager 类
- 2.6 Client 类
- 2.7 Client 类的运行结果
- 2.8 总结
- 3 各角色之间的关系
- 3.1 角色
- 3.1.1 Colleague ( 同事 )
- 3.1.2 ConcreteColleague ( 具体的同事 )
- 3.1.3 Mediator ( 中介者 )
- 3.1.4 ConcreteMediator ( 具体的中介者 )
- 3.1.5 Client ( 客户端 )
- 3.2 类图
- 4 注意事项
- 5 在框架中的使用
- 6 优缺点
- 7 适用场景
- 8 总结
1 基本介绍
中介者模式(Mediator Pattern)是一种 行为型 设计模式,它降低了多个对象和类之间的 通信复杂性,通过引入一个中介对象来 封装 一系列对象之间的 交互,使得这些对象不需要直接相互引用。
2 案例
本案例让甲方将需求告知项目经理,然后项目经理将需求分发给前、后端开发人员,前、后端开发人员负责根据需求修改各自负责的代码。
2.1 Developer 抽象类
public abstract class Developer { // 开发人员
// 由于其子类的逻辑十分简单,无需向 mediator 发送消息,所以其子类没有直接使用 mediator
protected Mediator mediator; // 对应的中介者
public Developer(Mediator mediator) {
this.mediator = mediator;
}
protected abstract void modifyCode(String require); // 根据需求修改代码
}
2.2 FrontendDeveloper 类
public class FrontendDeveloper extends Developer { // 前端开发人员
public FrontendDeveloper(Mediator mediator) {
super(mediator);
}
@Override
protected void modifyCode(String require) {
System.out.println("前端开发人员根据需求「" + require + "」修改前端显示的代码");
}
}
2.3 BackendDeveloper 类
public class BackendDeveloper extends Developer { // 后端开发人员
public BackendDeveloper(Mediator mediator) {
super(mediator);
}
@Override
protected void modifyCode(String require) {
System.out.println("后端开发人员根据需求「" + require + "」修改前端显示的代码");
}
}
2.4 Mediator 接口
// 实现这个接口后,可以当项目的中介者,接收甲方的需求,通知前、后端开发人员修改代码
public interface Mediator {
void organizeMembers(); // 组织开发组的成员
void changeRequire(String require); // 甲方更改需求
}
2.5 ProjectManager 类
public class ProjectManager implements Mediator { // 项目经理
// 假设项目中只需要一个前端开发人员和一个后端开发人员
private FrontendDeveloper frontendDeveloper;
private BackendDeveloper backendDeveloper;
@Override
public void organizeMembers() {
// 组织了两个开发人员进行开发
frontendDeveloper = new FrontendDeveloper(this);
backendDeveloper = new BackendDeveloper(this);
}
@Override
public void changeRequire(String require) {
System.out.println("项目经理收到甲方更改的需求「" + require + "」");
frontendDeveloper.modifyCode(require);
backendDeveloper.modifyCode(require);
}
}
2.6 Client 类
public class Client { // 客户端,充当甲方,测试了项目经理更改需求的能力
public static void main(String[] args) {
Mediator pm = new ProjectManager();
pm.organizeMembers();
pm.changeRequire("增加一个 傻瓜式引导 的功能");
pm.changeRequire("增加一个 个性化内容推荐 的功能");
}
}
2.7 Client 类的运行结果
项目经理收到甲方更改的需求「增加一个 傻瓜式引导 的功能」
前端开发人员根据需求「增加一个 傻瓜式引导 的功能」修改前端显示的代码
后端开发人员根据需求「增加一个 傻瓜式引导 的功能」修改前端显示的代码
项目经理收到甲方更改的需求「增加一个 个性化内容推荐 的功能」
前端开发人员根据需求「增加一个 个性化内容推荐 的功能」修改前端显示的代码
后端开发人员根据需求「增加一个 个性化内容推荐 的功能」修改前端显示的代码
2.8 总结
在本案例中,甲方更改需求时,只需要通知项目经理即可,无需通知具体的开发人员,通知具体开发人员的任务由项目经理完成。此外,前后端开发人员员也不需要向对方提问应该如何达成需求,由项目经理来通知他们应该达成什么样的需求。这样就减少了对象之间的交流,只存在必要的交流,简化了对象之间的关系。
3 各角色之间的关系
3.1 角色
3.1.1 Colleague ( 同事 )
该角色负责 定义与 Mediator 角色进行通信的 接口。本案例中,Developer
抽象类扮演了该角色。
3.1.2 ConcreteColleague ( 具体的同事 )
该角色负责 实现 Colleague 角色定义的 接口。本案例中,FrontendDeveloper, BackendDeveloper
类都在扮演该角色。
3.1.3 Mediator ( 中介者 )
该角色负责 定义 创建 ConcreteColleague 角色的 接口 和 与其进行通信的 接口。本案例中,Mediator
接口扮演了该角色。
3.1.4 ConcreteMediator ( 具体的中介者 )
该角色负责 实现 Mediator 角色的接口。本案例中,ProjectManager
类扮演了该角色。
3.1.5 Client ( 客户端 )
该角色负责 创建 ConcreteMediator 角色的对象,并 使用它完成具体的业务逻辑。本案例中,Client
类扮演了该角色。
3.2 类图
说明:
- Colleague 中的
controlColleague()
方法用于与 Mediator 通信,根据 Mediator 的指示修改自己的状态。 - Mediator 可以是接口。
- Colleague 也可以是接口,不过需要将其聚合的 Mediator 放到所有 ConcreteColleague 中。
- 当 Colleague 是抽象类时,其
setMediator()
方法可以由构造器替换。
4 注意事项
- 中介者责任重大:中介者对象承担了较多的责任,它是所有对象之间通信的桥梁。因此,一旦中介者出现了问题,整个系统就可能受到影响。所以,在设计中介者时,需要确保其 稳定性 和 可靠性。
- 避免中介者对象复杂化:如果设计不当,中介者对象可能会变得过于复杂,难以理解和维护。在实际使用中,需要 特别注意中介者的设计,避免其承担过多的责任和功能。可以通过合理划分中介者的职责、采用模块化设计等方法来降低其复杂度。
- 系统灵活性的保持:虽然中介者模式提高了系统的灵活性,但 在设计时需要确保系统仍然能够应对未来的变化。例如,可以通过定义 可扩展的中介者接口、使用 策略模式 等方法来增强系统的可扩展性。
- 性能考虑:在某些情况下,通过中介者进行 间接交互 可能比 直接交互 具有更高的性能开销。因此,在设计完成后,需要对系统的性能进行测试,并根据测试结果进行优化。例如,可以通过优化中介者的内部实现、减少不必要的通信等方法来提高系统性能。
5 在框架中的使用
在流行的 Java 框架中,使用了中介者模式的思想:
- MVC 框架:在 MVC(Model-View-Controller)框架 中,控制器(Controller)充当了 模型(Model)和 视图(View)之间的中介者。控制器负责接收用户的输入,并将其转换为模型可以理解的格式,同时,当模型状态发生变化时,控制器也会负责通知视图进行更新。这种设计使得模型、视图和控制器之间的耦合度降低,提高了系统的可维护性和可扩展性。
- 消息中间件:在分布式系统中,消息中间件(如 RabbitMQ、Kafka 等)也体现了中介者模式的思想。消息中间件 作为消息的 生产者 和 消费者 之间的中介,负责消息的存储和转发,使得生产者和消费者之间不需要直接进行通信,从而降低了系统的耦合度,提高了系统的可靠性和可扩展性。
6 优缺点
优点:
- 解耦与结构转换:多个类相互耦合 容易形成 网状结构,复杂且难以维护。使用中介者模式可以将 网状结构 分离为 星型结构,通过中介者对象进行通信,从而实现解耦。
- 符合迪米特法则(降低对象间的耦合度):中介者模式使得 对象之间不需要知道彼此的具体实现细节,只需通过中介者进行通信,这符合 迪米特法则,有助于减少对象之间的 耦合度。这使得对象之间的依赖关系更加简单,系统的结构更加清晰。
- 易于扩展和维护:当系统中需要增加新的对象或改变对象之间的交互方式时,只需修改中介者对象即可,而无需修改其他对象,这降低了系统 扩展 和 维护 的复杂性。
- 提高系统的灵活性:通过更换不同的中介者对象,可以灵活地改变对象之间的交互逻辑,从而增加系统的 灵活性。
缺点:
- 中介者可能变得复杂:如果系统中存在大量的对象,并且这些对象之间的交互关系非常复杂,那么中介者对象可能会变得非常庞大和复杂。这会增加中介者对象的维护难度,并可能导致代码难以理解和修改。
- 对中介者的依赖:由于 所有对象之间的交互都通过中介者进行,因此 系统对中介者的依赖程度较高。如果中介者出现故障或设计不当,可能会影响整个系统的正常运行。
- 可能隐藏系统复杂性:中介者模式可能会 隐藏对象之间的 直接交互关系,使得系统的整体结构和交互逻辑变得不够直观。这可能会给开发人员带来一定的理解难度,尤其是在处理复杂的系统时。
- 更高的性能开销:在某些情况下,通过中介者进行 间接交互 可能比 直接交互 具有 更高的性能开销。虽然这种开销在大多数情况下是可以接受的,但在性能敏感的应用中可能需要谨慎考虑。
7 适用场景
- 引用关系复杂的系统:
- 当 系统中对象之间存在复杂的引用关系,且 这些引用关系导致系统结构混乱、难以理解 时,可以考虑使用中介者模式。通过引入中介者对象,可以封装对象之间的交互细节,降低系统的复杂度。
- 例如,在 电商平台 中,卖家、买家、物流公司和支付平台之间可能存在复杂的交互关系,可以通过增加一个“消费中介”来分离它们之间的关系。
- 需要改变行为的系统:
- 如果 系统中对象之间的交互行为需要频繁变更,且 这些变更会影响到多个对象 时,可以使用中介者模式。通过增加新的中介者类,可以轻松地实现行为的扩展和变更,而无需修改原有对象。
- 例如,在 多人聊天室场景 中,如果需要变更消息的传递方式(如从文本消息变为语音消息),可以通过增加一个新的中介者类来实现,而无需修改用户对象。
- 高耦合的系统:
- 当 系统中对象之间的耦合度较高,且 这种耦合度影响了系统的可维护性和可扩展性 时,可以考虑使用中介者模式。通过中介者对象来封装对象之间的交互,可以降低对象之间的耦合度,使系统更加灵活和易于维护。
- 例如,在 MVC 框架中,控制器(Controller)作为模型(Model)和视图(View)之间的中介者,降低了它们之间的耦合度。当需要修改视图或模型的实现时,只需修改控制器即可,而无需修改其他组件。
- 集中化交互管理的系统:
- 在某些场景中,可能 需要一个中心化的对象来管理多个对象之间的交互。此时,可以使用中介者模式来实现。中介者对象负责接收来自各个对象的请求,并根据一定的规则将这些请求转发给相应的对象进行处理。
- 例如,在交通控制系统中,交通灯可以作为中介者对象来管理车辆和行人的交互。交通灯根据当前的道路情况和交通规则来控制车辆和行人的通行。
8 总结
中介者模式 是一种 行为型 设计模式,它通过引入 中介,组织了系统中各个对象之间的关系,从 网状关系 简化到 星型关系,降低了系统的耦合度,提高了系统的灵活性。不过,给对象之间添加一个中介会导致性能的下降,如果对性能要求很高,最好不要使用本模式。