【再谈设计模式】中介者模式 - 协调对象间交互的枢纽

一、引言

        在软件工程,软件开发过程中,复杂的软件系统,对象之间的交互往往错综复杂。当众多对象相互依赖、频繁通信时,系统的耦合度会急剧上升,导致代码难以维护、扩展和理解。就像在一个大型社交聚会中,如果每个人都直接与其他人交流,场面会变得混乱不堪。中介者模式的出现,就如同一位社交组织者,它简化了对象之间的交互关系,使系统更加有序和易于管理。

二、定义与描述

        中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。

三、抽象背景

        在面向对象的软件设计中,随着系统功能的不断增加,对象之间的交互逻辑会变得越来越复杂。例如,在一个图形用户界面(GUI)系统中,多个按钮、文本框和菜单之间可能存在复杂的交互关系,如点击按钮可能会影响文本框的显示内容,菜单的选择可能会改变按钮的可用性等。如果不采用合适的设计模式,这些对象之间的直接交互会导致代码的高度耦合,任何一个对象的改变都可能影响到其他多个对象。

四、适用场景与现实问题解决

(一)适用场景

GUI组件交互

        在桌面应用程序的GUI开发中,多个控件(如按钮、文本框、下拉菜单等)之间存在复杂的交互逻辑。中介者模式可以将这些控件之间的交互逻辑封装在中介者对象中,使得每个控件只需与中介者对象交互,而不需要知道其他控件的具体情况。

游戏开发中的角色交互

        在多人游戏中,不同角色之间可能存在各种交互,如交易、战斗、组队等。使用中介者模式可以将角色之间的交互逻辑集中管理,便于游戏逻辑的维护和扩展。

分布式系统中的节点通信

        在分布式系统中,多个节点需要相互通信以协调工作。中介者模式可以通过一个中介节点来管理其他节点之间的通信,简化通信协议和逻辑。

(二)现实问题解决

降低耦合度

        传统的对象间直接交互会导致对象之间紧密耦合,一个对象的变化可能需要修改多个与之相关的对象。中介者模式将对象间的交互转移到中介者对象中,使得对象之间的依赖关系减少。例如,在一个电商系统中,订单处理、库存管理和用户通知等模块之间存在复杂的交互。如果采用中介者模式,这些模块只需与中介者交互,当订单处理模块发生变化时,不会直接影响库存管理和用户通知模块,只需要调整中介者中的相关逻辑即可。

 

简化复杂交互逻辑

        当多个对象之间存在多对多的交互关系时,交互逻辑会变得非常复杂。中介者模式将这些复杂的交互逻辑集中到中介者对象中,使得系统的整体逻辑更加清晰。例如,在一个航空订票系统中,乘客、航班、航空公司等多个对象之间存在复杂的交互关系,如航班变更时需要通知乘客和航空公司进行相应的调整。通过中介者模式,可以将这些交互逻辑集中到一个订票中介者对象中,便于管理和维护。

五、中介者模式的现实生活的例子

机场塔台

        在机场中,飞机(多个对象)之间不能直接相互指挥飞行路径等操作,而是通过机场塔台(中介者)来协调。塔台接收来自各个飞机的请求(如起飞、降落、等待等),并根据整体的机场运行情况(如跑道占用、天气状况等)向飞机发出指令,以确保机场的安全和高效运行。

 

房屋中介

        在房地产交易中,卖家和买家(多个对象)之间通常不会直接协商房屋交易的所有细节。房屋中介(中介者)作为中间角色,收集卖家的房屋信息和价格期望,以及买家的购房需求和预算,然后协调双方进行看房、议价等活动,最终促成交易。

六、初衷与问题解决

初衷

        中介者模式的初衷是为了降低对象之间的耦合度,提高系统的可维护性和可扩展性。当系统中的对象数量增加,对象之间的交互关系变得复杂时,通过引入中介者对象,可以将复杂的多对多交互关系简化为对象与中介者之间的一对多关系。

问题解决

        如前面所述,它解决了对象之间的高度耦合问题,使得系统在面临需求变更或功能扩展时,不需要对大量的对象进行修改。同时,也简化了复杂的交互逻辑,提高了系统的整体清晰度,便于开发人员理解和维护系统。

七、代码示例

类图:

(一)Java示例

// 中介者接口
interface Mediator {void notify(Colleague colleague);
}// 同事类抽象类
abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator = mediator;}abstract void receive();abstract void send();
}// 具体同事类A
class ConcreteColleagueA extends Colleague {public ConcreteColleagueA(Mediator mediator) {super(mediator);}@Overridevoid receive() {System.out.println("ConcreteColleagueA received a message");}@Overridevoid send() {System.out.println("ConcreteColleagueA sends a message");mediator.notify(this);}
}// 具体同事类B
class ConcreteColleagueB extends Colleague {public ConcreteColleagueB(Mediator mediator) {super(mediator);}@Overridevoid receive() {System.out.println("ConcreteColleagueB received a message");}@Overridevoid send() {System.out.println("ConcreteColleagueB sends a message");mediator.notify(this);}
}// 具体中介者类
class ConcreteMediator implements Mediator {private ConcreteColleagueA colleagueA;private ConcreteColleagueB colleagueB;public void setColleagueA(ConcreteColleagueA colleagueA) {this.colleagueA = colleagueA;}public void setColleagueB(ConcreteColleagueB colleagueB) {this.colleagueB = colleagueB;}@Overridepublic void notify(Colleague colleague) {if (colleague == colleagueA) {colleagueB.receive();} else {colleagueA.receive();}}
}// 测试类
public class MediatorPatternJava {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);colleagueA.send();colleagueB.send();}
}

流程图:

时序图:

(二)C++示例

#include <iostream>// 中介者类
class Mediator {
public:virtual void notify(class Colleague *colleague) = 0;
};// 同事类抽象类
class Colleague {
protected:Mediator *mediator;
public:Colleague(Mediator *m) : mediator(m) {}virtual void receive() = 0;virtual void send() = 0;
};// 具体同事类A
class ConcreteColleagueA : public Colleague {
public:ConcreteColleagueA(Mediator *m) : Colleague(m) {}void receive() override {std::cout << "ConcreteColleagueA received a message" << std::endl;}void send() override {std::cout << "ConcreteColleagueA sends a message" << std::endl;mediator->notify(this);}
};// 具体同事类B
class ConcreteColleagueB : public Colleague {
public:ConcreteColleagueB(Mediator *m) : Colleague(m) {}void receive() override {std::cout << "ConcreteColleagueB received a message" << std::endl;}void send() override {std::cout << "ConcreteColleagueB sends a message" << std::endl;mediator->notify(this);}
};// 具体中介者类
class ConcreteMediator : public Mediator {
private:ConcreteColleagueA *colleagueA;ConcreteColleagueB *colleagueB;
public:void setColleagueA(ConcreteColleagueA *a) {colleagueA = a;}void setColleagueB(ConcreteColleagueB *b) {colleagueB = b;}void notify(Colleague *colleague) override {if (colleague == colleagueA) {colleagueB->receive();} else {colleagueA->receive();}}
};// 测试函数
int main() {ConcreteMediator mediator;ConcreteColleagueA colleagueA(&mediator);ConcreteColleagueB colleagueB(&mediator);mediator.setColleagueA(&colleagueA);mediator.setColleagueB(&colleagueB);colleagueA.send();colleagueB.send();return 0;
}

(三)Python示例

# 中介者类
class Mediator:def notify(self, colleague):pass# 同事类抽象类
class Colleague:def __init__(self, mediator):self.mediator = mediatordef receive(self):passdef send(self):pass# 具体同事类A
class ConcreteColleagueA(Colleague):def receive(self):print("ConcreteColleagueA received a message")def send(self):print("ConcreteColleagueA sends a message")self.mediator.notify(self)# 具体同事类B
class ConcreteColleagueB(Colleague):def receive(self):print("ConcreteColleagueB received a message")def send(self):print("ConcreteColleagueB sends a message")self.mediator.notify(self)# 具体中介者类
class ConcreteMediator(Mediator):def __init__(self):self.colleagueA = Noneself.colleagueB = Nonedef set_colleagueA(self, colleagueA):self.colleagueA = colleagueAdef set_colleagueB(self, colleagueB):self.colleagueB = colleagueBdef notify(self, colleague):if colleague == self.colleagueA:self.colleagueB.receive()else:self.colleagueA.receive()# 测试代码
if __name__ == "__main__":mediator = ConcreteMediator()colleagueA = ConcreteColleagueA(mediator)colleagueB = ConcreteColleagueB(mediator)mediator.set_colleagueA(colleagueA)mediator.set_colleagueB(colleagueB)colleagueA.send()colleagueB.send()

(四)Go示例

package mainimport ("fmt"
)// 中介者接口
type Mediator interface {notify(colleague Colleague)
}// 同事类接口
type Colleague interface {receive()send()
}// 具体同事类A
type ConcreteColleagueA struct {mediator Mediator
}func (c *ConcreteColleagueA) receive() {fmt.Println("ConcreteColleagueA received a message")
}func (c *ConcreteColleagueA) send() {fmt.Println("ConcreteColleagueA sends a message")c.mediator.notify(c)
}// 具体同事类B
type ConcreteColleagueB struct {mediator Mediator
}func (c *ConcreteColleagueB) receive() {fmt.Println("ConcreteColleagueB received a message")
}func (c *ConcreteColleagueB) send() {fmt.Println("ConcreteColleagueB sends a message")c.mediator.notify(c)
}// 具体中介者类
type ConcreteMediator struct {colleagueA *ConcreteColleagueAcolleagueB *ConcreteColleagueB
}func (m *ConcreteMediator) notify(colleague Colleague) {if _, ok := colleague.(*ConcreteColleagueA); ok {m.colleagueB.receive()} else {m.colleagueA.receive()}
}func main() {mediator := &ConcreteMediator{}colleagueA := &ConcreteColleagueA{mediator}colleagueB := &ConcreteColleagueB{mediator}mediator.colleagueA = colleagueAmediator.colleagueB = colleagueBcolleagueA.send()colleagueB.send()
}

八、中介者模式的优缺点

(一)优点

降低耦合度

        对象之间不再直接交互,而是通过中介者进行通信,大大降低了对象之间的依赖关系,使得系统更加灵活,易于维护和扩展。

简化对象交互逻辑

        将复杂的多对多对象交互逻辑集中到中介者对象中,使得交互逻辑更加清晰,便于理解和管理。

提高代码复用性

        中介者对象可以被多个对象复用,提高了代码的复用性。

 

(二)缺点

中介者可能变得复杂

        随着系统功能的增加,中介者对象可能会承担过多的交互逻辑,变得过于复杂,难以维护。

降低对象的自主性

        对象的行为在一定程度上依赖于中介者,可能会降低对象自身的自主性和可复用性。

分类描述
(一)优点
降低耦合度对象之间通过中介者通信,降低对象间依赖关系,系统更灵活、易维护和扩展。
简化对象交互逻辑复杂多对多交互逻辑集中到中介者,使交互逻辑更清晰、便于理解管理。
提高代码复用性中介者可被多个对象复用。
(二)缺点
中介者可能变得复杂系统功能增加时,中介者可能承担过多逻辑,难以维护。
降低对象的自主性对象行为依赖中介者,可能降低自身自主性和复用性。

九、中介者模式的升级版

分层中介者模式

        在大型系统中,可以采用分层中介者模式。将中介者分为多个层次,每个层次的中介者负责处理特定范围内的对象交互。例如,在企业级应用中,可以有部门级中介者和公司级中介者。部门级中介者处理部门内部对象的交互,公司级中介者协调部门之间的交互。这种分层结构可以进一步降低耦合度,提高系统的可维护性和扩展性。

分布式中介者模式

        在分布式系统中,可以采用分布式中介者模式。将中介者功能分布在多个节点上,通过网络通信来协调对象之间的交互。这种模式可以提高系统的容错性和性能,适用于大规模分布式应用场景。

模式优势(Strengths)劣势(Weaknesses)机会(Opportunities)威胁(Threats)
分层中介者模式- 降低大型系统耦合度,提高可维护性和扩展性
- 明确不同层次中介者的职责范围,便于管理
- 增加系统复杂性,多层中介者间协调可能存在问题
- 层次划分不当可能导致职责混乱
- 适应企业级架构演进需求
- 可与其他企业级模式整合
- 企业架构变革可能使分层结构失效
- 竞争模式可能更具优势
分布式中介者模式- 提高分布式系统的容错性
- 提升大规模分布式应用场景下的性能
- 网络通信可能带来延迟和可靠性问题
- 分布式协调增加了复杂度
- 适用于新兴的分布式计算趋势
- 可利用云计算资源提升性能
- 网络攻击可能破坏分布式协调
- 新技术可能替代该模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/69561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络工程师 (29)CSMA/CD协议

前言 CSMA/CD协议&#xff0c;即载波监听多路访问/碰撞检测&#xff08;Carrier Sense Multiple Access with Collision Detection&#xff09;协议&#xff0c;是一种在计算机网络中&#xff0c;特别是在以太网环境下&#xff0c;用于管理多个设备共享同一物理传输介质的重要…

Jenkins设置防火墙规则允许访问本机IP端口

netsh advfirewall firewall add rule name"Jenkins_8080" dirin actionallow protocolTCP localport8080命令组成部分 netsh - 网络配置命令行工具advfirewall firewall - 高级防火墙配置add rule - 添加新规则name"Jenkins_8080" - 规则名称dirin - 入站…

对于索引,在开发中需要注意什么?

目录 1. 索引的设计原则 2. 索引的类型选择 3. 索引的使用注意事项 4. 索引的性能优化 5. 索引的常见问题 6. 实际开发中的最佳实践 7. 示例 创建索引 分析查询计划 强制使用索引 总结 在开发中使用索引时,需要注意以下几个方面,以确保索引能够有效提升查询性能,…

软件项目验收测试有哪些类型?

在信息技术行业&#xff0c;软件项目的成功不仅依赖于开发能力&#xff0c;更在于准确的验收测试。验收测试是软件开发生命周期中的重要一环。其主要目的是验证软件系统是否符合用户需求和预期。在这一阶段&#xff0c;最终用户能够直观地判断软件是否满足其业务需求。 软件项…

Python截图轻量化工具

一、兼容局限性 这是用Python做的截图工具&#xff0c;不过由于使用了ctypes调用了Windows的API, 同时访问了Windows中"C:/Windows/Cursors/"中的.cur光标样式文件, 这个工具只适用于Windows环境&#xff1b; 如果要提升其跨平台性的话&#xff0c;需要考虑替换cty…

C++ labmbd表达式

文章目录 C++ Lambda 表达式详解1. Lambda 表达式的组成部分:2. Lambda 语法示例(1) 最简单的 Lambda(2) 带参数的 Lambda(3) 指定返回类型的 Lambda3. 捕获外部变量(1) 值捕获(复制)(2) 引用捕获(3) 捕获所有变量4. Lambda 在 STL 中的应用5. Lambda 作为 `std::function`6…

【Deepseek私有化部署】解决 Anything LLM 上传文档一直转圈上传失败问题

这里写自定义目录标题 一、问题描述二、原因分析&#xff08;一&#xff09;Embedder 在 Anything LLM 中的核心作用&#xff08;二&#xff09;默认配置与 Deepseek 的适配问题&#xff08;三&#xff09;未正确配置 nomic - embed - text 引发的异常 三、解决途径&#xff08…

神经网络|(九)概率论基础知识-泊松分布及python仿真

【1】引言 在前序学习进程中&#xff0c;我们已经知晓二项分布是多重伯努利分布&#xff0c;二伯努利分布对应的是可以无限重复、结果只有两种可能的随机试验。 相关文章链接为&#xff1a; 神经网络|(八)概率论基础知识-二项分布及python仿真-CSDN博客 上述文章还调用nump…

使用 OpenGL ES 渲染一个四边形

使用 OpenGL ES 渲染一个四边形 在 iOS 开发中,OpenGL ES 是一个强大的工具,用于实现高性能的 2D 和 3D 图形渲染。本文将通过一个完整的代码示例,详细解析如何使用 OpenGL ES 渲染一个简单的四边形。我们将从基础概念入手,逐步讲解代码的每个部分,帮助你理解 OpenGL ES …

《从0到1CTFer成长之路》逆向工程个人笔记--静态分析

上一篇文章&#xff1a;《从0到1CTFer成长之路》逆向工程个人笔记--逆向工程基础 IDA 使用入门 加载文件 打开 IDA&#xff0c;点击 GO&#xff0c;即可把程序拖拽到 IDA 中 IDA 分为 32bit 和 64bit 两种架构&#xff0c;选择哪种结构&#xff0c;可以在把程序拖拽到 IDA 后…

【机器学习】训练(Training)、验证(Validation)和测试(Testing)

机器学习中训练(Training)、验证(Validation)和测试(Testing)这三个阶段的作用和关系。 1. 训练阶段 (Training) - 使用训练集数据来训练模型 - 模型通过学习训练数据的特征和模式来调整其内部参数 - 这个阶段模型会不断优化以减少预测误差 - 通常使用最大的数据集比例&…

解锁 DeepSeek 模型高效部署密码:蓝耘平台深度剖析与实战应用

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

SQL自学,mysql从入门到精通 --- 第 15天,数据导入、导出

数据的导入、导出 -- 查看当前设置的目录路径,限制从数据库服务器读取和写入文件的操作只能在指定的目录中进行,在安全性和文件操作限制方面具有重要意义。root@mysqldb 14:19: [(none)]> SHOW VARIABLES LIKE "secure_file_priv"; +------------------+------…

IDEA升级出现问题Failed to prepare an update Temp directory inside installation

IDEA升级出现问题"Failed to prepare an update Temp directory inside installation…" 问题来源&#xff1a; 之前修改了IDEA的默认配置文件路径&#xff0c;然后升级新版本时就无法升级&#xff0c;提示"Failed to prepare an update Temp directory insid…

Faiss特征向量搜索

ubuntu 24.10系统上实现 安装OpenBLAS git clone https://github.com/xianyi/OpenBLAS.git 安装gfortran进行编译 sudo apt install gfortran cd OpenBLAS make FCgfortran make install ln -s /opt/OpenBLAS/lib/libopenblas.so /usr/lib/libopenblas.so LD_LIBRARY_PATH/…

查询已经运行的 Docker 容器启动命令

一、导语 使用 get_command_4_run_container 查询 docker 容器的启动命令 获取镜像 docker pull cucker/get_command_4_run_container 查看容器命令 docker run --rm -v /var/run/docker.sock:/var/run/docker.sock cucker/get_command_4_run_container 容器id或容器名 …

【C++高并发服务器WebServer】-14:Select详解及实现

本文目录 一、BIO模型二、非阻塞NIO忙轮询三、IO多路复用四、Select()多路复用实现 明确一下IO多路复用的概念&#xff1a;IO多路复用能够使得程序同时监听多个文件描述符&#xff08;文件描述符fd对应的是内核读写缓冲区&#xff09;&#xff0c;能够提升程序的性能。 Linux下…

活动预告 |【Part1】Microsoft 安全在线技术公开课:安全性、合规性和身份基础知识

课程介绍 通过参加“Microsoft 安全在线技术公开课&#xff1a;安全性、合规性和身份基础知识”活动提升你的技能。在本次免费的介绍性活动中&#xff0c;你将获得所需的安全技能和培训&#xff0c;以创造影响力并利用机会推动职业发展。你将了解安全性、合规性和身份的基础知识…

Dubbo 3.x源码(29)—Dubbo Consumer服务调用源码(1)服务调用入口

基于Dubbo 3.1&#xff0c;详细介绍了Dubbo Consumer服务调用源码。 此前我们学习了Dubbo服务的导出和引入的源码&#xff0c;现在我们来学习Dubbo服务调用的源码。 此前的文章中我们讲过了最上层代理的调用逻辑(服务引用bean的获取以及懒加载原理)&#xff1a;业务引入的接口…

java-初识List

List&#xff1a; List 是一个接口&#xff0c;属于 java.util 包&#xff0c;用于表示有序的元素集合。List 允许存储重复元素&#xff0c;并且可以通过索引访问元素。它是 Java 集合框架&#xff08;Java Collections Framework&#xff09;的一部分 特点&#xff1a; 有序…