十九、中介者模式
文章目录
- 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 发送消息,所以其子类没有直接使用 mediatorprotected 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);}@Overrideprotected void modifyCode(String require) {System.out.println("前端开发人员根据需求「" + require + "」修改前端显示的代码");}
}
2.3 BackendDeveloper 类
public class BackendDeveloper extends Developer { // 后端开发人员public BackendDeveloper(Mediator mediator) {super(mediator);}@Overrideprotected 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;@Overridepublic void organizeMembers() {// 组织了两个开发人员进行开发frontendDeveloper = new FrontendDeveloper(this);backendDeveloper = new BackendDeveloper(this);}@Overridepublic 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 总结
中介者模式 是一种 行为型 设计模式,它通过引入 中介,组织了系统中各个对象之间的关系,从 网状关系 简化到 星型关系,降低了系统的耦合度,提高了系统的灵活性。不过,给对象之间添加一个中介会导致性能的下降,如果对性能要求很高,最好不要使用本模式。
相关文章:

十九、中介者模式
文章目录 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 ( 具体的…...
编程参考 - 头文件中使用static inline
在Linux kernel的头文件中,经常使用static inline来声明一个函数。 比如include/linux/delay.h中, static inline void ssleep(unsigned int seconds) { msleep(seconds * 1000); } static Keyword * 范围限制: 当应用于函数或变量时&#…...
Uniapp使用antd组件库
组件库官网 https://www.antdv.com/docs/vue/introduce-cn 安装 在命令行终端输入 npm uni --save ant-design-vue配置 我这里用的是uniapp的vue3版本模板 在main.js里面引入 只要改下面带序号的地方即可 import App from ./App// #ifndef VUE3 import Vue from vue im…...

计算机毕业设计选题推荐-高校实验室管理系统-Java/Python项目实战
✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…...
nest定义响应码message文本
需求 需要对接口的异常响应码,手动设置message文本!!! 例如:项目中使用multer中间件实现文件上传,multer设置了文件大小限制,该中间件校验文件时错误(文件超出)会自动响…...

Java | Leetcode Java题解之第342题4的幂
题目: 题解: class Solution {public boolean isPowerOfFour(int n) {return n > 0 && (n & (n - 1)) 0 && n % 3 1;} }...
【日常开发】java中一个list对象集合 将字段a为 大豆 小麦 玉米等元素放在最前面 并组成新集合
🎈边走、边悟🎈迟早会好 在Java中实现这个功能,可以使用Stream来筛选出符合条件的元素,将它们放在新集合的前面,同时保留其他元素在新集合的后面。以下是如何实现的代码示例: 代码示例: impo…...

C++ 设计模式——原型模式
原型模式 原型模式主要组成部分原型模式的使用步骤原型模式的 UML 图原型模式 UML 图解析优点和缺点适用场景总结 原型模式 原型(Prototype)模式是一种创建型模式。原型模式通过(原型对象)克隆出对个一模一样的对象。实际上,该模式与其说是一种设计模式,…...

【Harmony OS 4.0】待办列表案例
src/main/ets/example1/Models.ets // 定义class类数据模型 export class TaskDataModel {// private 私有属性,在类对象外不允许随意更改数据,必须本地初始化。private tasks: Array<string> [早起晨练, 准备早餐, 阅读名著, 学习ArkTs, 玩游戏…...

快速把文件名统计到excel表的方法
文件名统计到EXCEL表,这似乎很多人都没听说过,因为它与EXCEL表格不沾边,那么这个需求如何实现,用到什么方法,今天给大家介绍一个比较实用的方法,它可以把文件名或文件夹的名快速提取并统计到EXCEL表格上去。…...

开源通用验证码识别OCR —— DdddOcr 源码赏析(一)
文章目录 [toc] 前言DdddOcr环境准备安装DdddOcr使用示例 源码分析实例化DdddOcr实例化过程 分类识别分类识别过程 未完待续 前言 DdddOcr 源码赏析 DdddOcr DdddOcr是开源的通用验证码识别OCR 官方传送门 环境准备 安装DdddOcr pip install ddddocr使用示例 示例图片如…...
上升ECMAScript性能优化技巧与陷阱(下)
4. 深拷贝和浅拷贝的选择不当 在JavaScript中,对象是通过引用传递的,这意味着当你将一个对象赋值给另一个变量时,你实际上是在传递对象的引用,而不是对象本身。这导致了一个常见的问题:当你修改一个对象的属性时&…...

用7EPhone云手机进行TikTok的矩阵运营
“根据市局机构Statista发布的报告显示,截至2024年4月,TikTok全球下载量超过49.2亿次,月度活跃用户数超过15.82亿。TikTok的流量受欢迎程度可想而知,也一跃成为了全球第五大最受欢迎的社交APP。” 人群密集的地方社区也是适合推广…...

谷歌浏览器下载文件被阻止怎么解除
在工作生活中,我们会使用谷歌浏览器下载各种各样的文件,不过偶尔会遇到文件下载被阻止的情况。为了解决这一问题,本文为大家分享了实用的措施建议,一起来了解一下吧。(本文由https://chrome.cmrrs.com/站点的作者进行编…...

apt E: 无法定位软件包 winehq-stable
执行了 添加wine源 wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources还需要执行 更新源 apt update...
P2460[SDOI2007] 科比的比赛
第一次做洛谷系列,紧张,请多关照哦 题目传送门:[SDOI2007] 科比的比赛 - 洛谷 思路分析 这道题大概题意是给定我们的主人公 Kobe Bryant 的 mm 个对手,nn 场比赛相对应的获胜概率。求 Kobe Bryant 最大全部获胜概率和打败对手能…...

linux学习--第二天
--Linux文件系统 -显示文件命令 cat 1. cat -b 文件:从1开始对非空输出行编号 2. cat -n 文件:从1开始对所有行编号 3. cat -s 文件:将连续多行空白行合并 more(显示一屏文本内容) 1. more -num 文件ÿ…...
使用 Flask、Celery 和 Python 实现每月定时任务
为了创建一个使用 Flask、Celery 和 Python 实现的每月定时任务,我们需要按照以下步骤进行: 1.安装必要的库 我们需要安装 Flask、Celery 和 Redis(作为消息代理)。我们可以使用 pip 来安装它们: bash复制代码 p…...

【c语言】整数在内存中的储存(大小端字节序)
整数在内存中的储存(大小端字节序) 1.整数在内存中的储存 2.大小端字节序 3.整数在内存中储存例子 4.字节序判断 5.死循环现象 文章目录 整数在内存中的储存(大小端字节序)整数在内存中的储存大小端字节序什么是大小端为什么会有…...

浅谈SIMD、向量化处理及其在StarRocks中的应用
前言 单指令流多数据流(SIMD)及其衍生出来的向量化处理技术已经有了相当的历史,并且也是高性能数据库、计算引擎、多媒体库等组件的标配利器。笔者在两年多前曾经做过一次有关该主题的内部Geek分享,但可能是由于这个topic离实际研发场景比较远࿰…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...