当前位置: 首页 > news >正文

C++设计模式——Mediator中介者模式

一,中介者模式的定义

中介者模式是一种行为型设计模式。它通过一个中介者对象将多个对象之间的交互关系进行封装,使得对象之间的交互需要通过中介者对象来完成。该设计模式的结构很容易理解,以中介者为中心。

中介者模式的设计思想侧重于在对象之间增加一个用来调度的中介。

有了中介者模式,各个对象可以专注于各自的业务处理逻辑,而不需要关心通信的具体实现细节。

中介者模式在现实生活中的抽象实例:

航空管制系统:航空管制系统作为中介者,协调飞机、航空公司和机场的通信和协作。

交易系统:在金融领域,交易系统将银行、金融机构、客户等各个参与者进行协调,确保资金的安全快速转移。

买房中介:买房中介充当着买卖双方之间的桥梁和调解者的角色,确保双方利益的平衡和交易的顺利进行。

二,中介者模式的结构

中介者模式主要包含以下组件:

1.抽象中介者(Mediator):定义了对象之间相互通信的规则,定义了管理对象和消息通信的统一接口。

2.抽象同事对象(Colleague):是参与通信的各个对象,内部包含对中介者对象的引用。负责将消息发送给中介者,以及接收并处理中介者发来的消息。

3.具体中介者(Concrete Mediator):包含对抽象中介者的具体实现,负责协调各个对象之间的通信,协调的方式以转发消息为主。

4.具体同事对象(Concrete Colleague):包含对抽象同事对象的具体实现。它们之间通过调用中介者的接口进行通信,并接收和处理中介者转发给它们的消息。

组件之间的工作步骤如下:

1.初始化中介者对象。

2.各个同事对象与中介者关联,将中介者对象传递给各个同事对象。

3.同事对象与中介者通信,同事对象调用中介者对象提供的通信接口,由中介者负责将信息转发给目标同事对象。

对应UML类图:

三,中介者模式代码样例

#include <iostream>
#include <string>
#include <vector>class Colleague;class Mediator{
public:virtual void sendMessage(const std::string& msg, Colleague* colleague) = 0;virtual void addColleague(Colleague* colleague) = 0;
};class Colleague{
public:Colleague(Mediator* mediator) : mediator_(mediator) {}virtual void sendMessage(const std::string& message) = 0;virtual void receiveMessage(const std::string& message) = 0;
protected:Mediator* mediator_;
};class ConcreteMediator : public Mediator{
public:void sendMessage(const std::string& msg, Colleague* colleague) override{for (auto col : colleagues_) {if (col != colleague) {col->receiveMessage(msg);}}}void addColleague(Colleague* colleague) override {colleagues_.push_back(colleague);}
private:std::vector<Colleague*> colleagues_;
};class ConcreteColleague : public Colleague{
public:ConcreteColleague(Mediator* mediator) : Colleague(mediator) {}void sendMessage(const std::string& message) override {mediator_->sendMessage(message, this);}void receiveMessage(const std::string& message) override {std::cout << "Received message: " << message << std::endl;}
};int main() {Mediator* mediator = new ConcreteMediator();Colleague* colleague1 = new ConcreteColleague(mediator);Colleague* colleague2 = new ConcreteColleague(mediator);mediator->addColleague(colleague1);mediator->addColleague(colleague2);colleague1->sendMessage("Hello from colleague1");colleague2->sendMessage("Hello from colleague2");delete colleague1;delete colleague2;delete mediator;return 0;
}

运行结果:

Received message: Hello from colleague1
Received message: Hello from colleague2

四,中介者模式的应用场景

事件驱动架构:应用程序中,按钮点击等事件不需要直接关联所有处理响应的逻辑,而是通过一个“事件总线”或“消息中间件”来分发消息。

GUI用户界面:在UI组件间传递事件或更新状态时,可以使用中介者模式避免硬编码依赖。

分布式系统:分布式应用中设定一个集中式的服务器作为中介,协调客户端之间的交互。

消息队列:在异步通信场景,发送者和接收者通过一个消息中间件来传递信息,方便解耦和事务管理。

五,中介者模式的优缺点

中介者模式的优点:

降低了对象之间的耦合,易于维护。

可以实现对通信的集中控制。

方便随时修改和消息对应的事件处理。

在不改变原有对象的基础上,可以灵活添加新的消息类型。

中介者模式的缺点:

容易导致对系统的过度设计。

当对象很多时,中介者会变得复杂和难以管理。

通信期间需要额外的调度,性能开销大。

六,代码实战

Demo1:基于中介者模式实现的消息群发功能

#include <iostream>
#include <string>
#include <vector>class User;class Mediator {
public:virtual void sendMessage(const std::string& message, User* user) = 0;virtual void addUser(User* user) = 0;
};class User {
public:User(const std::string& name, Mediator* mediator){this->name = name;this->mediator = mediator;}const std::string& getName() const {return name;}void sendMessage(const std::string& message) {mediator->sendMessage(message, this);}virtual void receiveMsg(const std::string& message) = 0;
private:std::string name;Mediator* mediator;
};class ChatRoom : public Mediator {
public:void addUser(User* user) {users.push_back(user);}void sendMessage(const std::string& message, User* sender) override {for (User* user : users) {if (user != sender) {user->receiveMsg(message);}}}
private:std::vector<User*> users;
};class ChatUser : public User {
public:ChatUser(const std::string& name, Mediator* mediator) : User(name, mediator) {}void receiveMsg(const std::string& msg) override {std::cout << getName() << " received a message: " << msg << std::endl;}
};int main() {Mediator* chatRoom = new ChatRoom();User* user1 = new ChatUser("User1", chatRoom);User* user2 = new ChatUser("User2", chatRoom);User* user3 = new ChatUser("User3", chatRoom);chatRoom->addUser(user1);chatRoom->addUser(user2);chatRoom->addUser(user3);user1->sendMessage("Hello, everyone!");delete user1;delete user2;delete user3;delete chatRoom;return 0;
}

运行结果:

User2 received a message: Hello, everyone!
User3 received a message: Hello, everyone!

Demo2:模拟的聊天室

#include <iostream>
#include <string>
#include <vector>using namespace std;struct ChatRoom {virtual void broadcast(string from, string msg) = 0;virtual void message(string from, string to, string msg) = 0;
};struct Person {string m_name;ChatRoom* m_room{ nullptr };vector<string> m_chat_log;Person(string n) : m_name(n) {}void say(string msg) const {m_room->broadcast(m_name, msg);}void pm(string to, string msg) const {m_room->message(m_name, to, msg);}void receive(string from, string msg) {string s{ from + ": \"" + msg + "\"" };cout << "[" << m_name << "'s chat session]" << s << "\n";m_chat_log.emplace_back(s);}
};struct GoogleChat: ChatRoom
{vector<Person*> m_people;void broadcast(string from, string msg) {for (auto p : m_people)if (p->m_name != from)p->receive(from, msg);}void join(Person* p) {string join_msg = p->m_name + " joins the chat";broadcast("room", join_msg);p->m_room = this;m_people.push_back(p);}void message(string from, string to, string msg) {auto target = find_if(begin(m_people), end(m_people),[&](const Person* p) {return p->m_name == to;});if (target != end(m_people)) (*target)->receive(from, msg);}
};int main() {GoogleChat room;Person john{ "John" };Person jane{ "Jane" };room.join(&john);room.join(&jane);john.say("hi room");jane.say("oh, hey john");Person simon{ "Simon" };room.join(&simon);simon.say("hi everyone!");jane.pm("Simon", "glad you found us, simon!");return EXIT_SUCCESS;
}

运行结果:

[John's chat session]room: "Jane joins the chat"
[Jane's chat session]John: "hi room"
[John's chat session]Jane: "oh, hey john"
[John's chat session]room: "Simon joins the chat"
[Jane's chat session]room: "Simon joins the chat"
[John's chat session]Simon: "hi everyone!"
[Jane's chat session]Simon: "hi everyone!"
[Simon's chat session]Jane: "glad you found us, simon!"

七,参考阅读

https://www.geeksforgeeks.org/mediator-design-pattern/

https://www.patterns.dev/vanilla/mediator-pattern/

https://vishalchovatiya.com/posts/mediator-design-pattern-in-modern-cpp/

https://softwarepatterns.com/cpp/mediator-software-pattern-cpp-example

相关文章:

C++设计模式——Mediator中介者模式

一&#xff0c;中介者模式的定义 中介者模式是一种行为型设计模式。它通过一个中介者对象将多个对象之间的交互关系进行封装&#xff0c;使得对象之间的交互需要通过中介者对象来完成。该设计模式的结构很容易理解&#xff0c;以中介者为中心。 中介者模式的设计思想侧重于在…...

微服务之间远程调用实现思路

项目使用的Spring Cloud Alibaba框架&#xff0c;微服务之间远程调用使用OpenFeign&#xff0c;具体实现步骤如下&#xff1a; &#xff08;1&#xff09;在api工程定义OpenFeign接口&#xff0c;使用FeignClient注解进行定义。 &#xff08;2&#xff09;服务提供方定义Open…...

获取STM32 MCU的唯一ID

STM32每个系列都会有唯一的一个芯片序列号&#xff08;96位bit&#xff09; STM32F10X 的起始地址是 0x1FFFF7E8 STM32F20X 的起始地址是 0x1FFF7A10 STM32F30X 的起始地址是 0x1FFFF7AC STM32F40X 的起始地址是 0x1FFF7A10 STM32L0XX 的起始地址是 0x1FF80050 STM32L1XX 的起…...

Debian项目实战——环境搭建篇

Debian系统安装 准备工作 1、系统镜像&#xff1a;根据自己的需要选择合适的版本格式&#xff1a;x86 / arm 架构 | 最好下载离线安装版本 | 清华镜像源 2、制作工具&#xff1a;balenaEtcher 3、系统媒介&#xff1a;16G以上U盘最佳 烧录镜像 打开balenaEtcher进行烧录&am…...

CenterNet官方代码—目标检测模型推理部分解析与项目启动

CenterNet模型推理部分解析 CenterNet官方代码环境部署 CenterNet作为2019年CVPR推出的论文&#xff0c;论文中给出了官方代码所在的github仓库地址。https://github.com/xingyizhou/CenterNet。 整个代码的代码量并不是特别大&#xff0c;但整个项目的难点在于使用了老版本的…...

测试开发基础——测试用例的设计

三、测试用例的设计 1. 什么是测试用例 测试用例(Test Case)是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 设计测试用例原则一&#xff1a;测试用例中一个必需部分是对预期输出或结果进…...

C++第五十一弹---IO流实战:高效文件读写与格式化输出

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 3.2.1 以写方式打开文件 3.2.1 以读方式打开文件 4 stringstre…...

C++中使用分治法求最大值

在C++中使用分治法(Divide and Conquer)来求一个数组中的最大值是一个经典的问题。分治法是一种通过将原问题分解为若干个小规模相似子问题,递归地求解这些子问题,然后将子问题的解合并成原问题的解的方法。 以下是使用分治法求数组中最大值的步骤: 分解(Divide):将数…...

数据集 CULane 车道线检测 >> DataBall

数据集 CULane 车道线检测 自动驾驶 无人驾驶目标检测 CULane是用于行车道检测学术研究的大规模具有挑战性的数据集。它由安装在六辆由北京不同驾驶员驾驶的不同车辆上的摄像机收集。收集了超过55小时的视频&#xff0c;并提取了133,235帧。数据示例如上所示。我们将数据集分为…...

Android CustomDialog圆角背景不生效的问题

一行解决: window?.setBackgroundDrawableResource(android.R.color.transparent) 原文件: /*** Created by Xinghai.Zhao* 自定义选择弹框*/ SuppressLint("InflateParams", "MissingInflatedId") class CustomDialog(context: Context?) : AlertDia…...

C++速通LeetCode简单第9题-二叉树的最大深度

深度优先算法递归&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right…...

com.microsoft.sqlserver:sqljdbc4:jar:4.0 was not found产生原因及解决步骤

文章目录 问题sqlserver 包找不到 报错原因分析主要原因 解决方案步骤 1&#xff1a;检查 pom.xml 中的依赖声明步骤 2&#xff1a;配置 Microsoft 的 Maven 仓库步骤 3&#xff1a;强制更新 Maven 依赖步骤 4&#xff1a;清理本地仓库缓存步骤 5&#xff1a;手动下载并安装 sq…...

【算法】 滑动窗口—最长无重复子串

“无重复字符的最长子串”&#xff0c;难度为Medium&#xff0c;看下题目&#xff1a; 输入一个字符串 s&#xff0c;请计算 s 中不包含重复字符的最长子串长度。 比如&#xff0c;输入 s "aabab"&#xff0c;算法返回2&#xff0c;因为无重复的最长子串是 "ab…...

SpringBoot2:web开发常用功能实现及原理解析-上传与下载

文章目录 一、上传文件1、前端上传文件给Java接口2、Java接口上传文件给Java接口 二、下载文件1、前端调用Java接口下载文件2、Java接口下载网络文件到本地3、前端调用Java接口下载网络文件 一、上传文件 1、前端上传文件给Java接口 Controller接口 此接口支持上传单个文件和…...

Linux:进程状态和优先级

一、进程状态 1.1 操作系统学科&#xff08;运行、阻塞、挂起&#xff09; 为了弄明白正在运行的进程是什么意思&#xff0c;我们需要知道进程的不同状态 大多数操作系统都遵循以下原则 1.1.1 运行状态 因为有一个调度器需要确保CPU的资源被合理使用&#xff0c;所以需要维护…...

代码随想录算法训练营day37

1.携带研究材料 1.1 题目 52. 携带研究材料&#xff08;第七期模拟笔试&#xff09; 1.2 题解 #include <iostream> #include <functional> #include <vector> using namespace std;int main() {//输入相关信息int classes, cabaity;cin >> classe…...

Java-idea小锤子图标

这一版的idea小锤子图标其实就在这里 点进去就找到了~...

最强神器Typora 2024(亲测有效)| Markdown 工具推荐

听俺讲一下 大家好&#xff0c;我是程序员-杨胡广&#xff0c;今天想给大家分享一个在编写文档时的神器——Typora。相信不少小伙伴都在寻找一款既简洁又强大的 Markdown 编辑工具&#xff0c;而 Typora 无疑是最值得推荐的选择。 当我在大学时偶然发现了它&#xff0c;直到今…...

【时时三省】tessy 单元测试 集成测试 专栏 文章阅读说明

目录 1&#xff0c;关于更新 2&#xff0c;关于文章阅读 3&#xff0c;关于文章分类 1&#xff0c;单元测试 2&#xff0c;集成测试 3&#xff0c;通用便捷操作 4&#xff0c;编译问题集锦 5&#xff0c;需求管理 6&#xff0c;CTE的使用 7&#xff0c;tessy自动化执…...

力扣刷题(6)

两数之和 II - 输入有序数组 两数之和 II - 输入有序数组-力扣 思路&#xff1a; 因为该数组是非递减顺序排列&#xff0c;因此可以设两个左右下标当左右下标的数相加大于target时&#xff0c;则表示右下标的数字过大&#xff0c;因此将右下标 - -当左右下标的数相加小于targ…...

东芝Toshiba e-STUDIO2110AC打印机信息

基本信息 产品类型&#xff1a;数码复合机颜色类型&#xff1a;彩色涵盖功能&#xff1a;复印、打印、扫描接口类型&#xff1a;标配为 Ethernet&#xff08;RJ45&#xff09;10/100/1000BASE - T、USB2.0 高速&#xff1b;选配为 Wireless Lan、IEEE802.11b/g/n、blueteeth。中…...

一个简单的德劳内三角剖分实现

德劳内&#xff08;Delaunay&#xff09;三角剖分是一种经典的将点集进行三角网格化预处理的手段&#xff0c;在NavMesh、随机地牢生成等场景下都有应用。 具体内容百度一大堆&#xff0c;就不介绍了。 比较知名的算法是Bowyer-Watson算法&#xff0c;也就是逐点插入法。 下雨闲…...

Python Cookbook-7.12 在 SQLite 中储存 BLOB

任务 想将 BLOB 存入一个 SQLite 数据库, 解决方案 Python的 PySQLite 扩展提供了 sqlite.encode 函数,它可帮助你在 SOLite 数据库中插入二进制串。可以基于这个函数编写一个小巧的适配器类: import sqlite,cPickle class Blob(object):自动转换二进制串def __init__(self…...

OkHttp 3.0源码解析:从设计理念到核心实现

本文通过深入分析OkHttp 3.0源码&#xff0c;揭示其高效HTTP客户端的实现奥秘&#xff0c;包含核心设计理念、关键组件解析、完整工作流程及实用技巧。 一、引言&#xff1a;为什么选择OkHttp&#xff1f; 在Android和Java生态中&#xff0c;OkHttp已成为HTTP客户端的标准选择…...

IDEA中的debug使用技巧

详细教学视频见b站链接&#xff1a;IDEA的debug调试 CSDN详细博客文章链接&#xff1a;debug文章学习 以下为个人学习记录总结&#xff1a; idea中的debug模式界面如下&#xff1a; 现在详细介绍图标作用&#xff1a; 图标一&#xff08;Show Execution Point&#xff09;&…...

中电金信:从智能应用到全栈AI,大模型如何重构金融业务价值链?

导语 当前&#xff0c;AI大模型技术正加速重构金融行业的智能化图景。为助力金融机构精准把握这一变革机遇&#xff0c;中电金信与IDC联合发布《中国金融大模型发展白皮书》。《白皮书》在梳理了AI大模型整体发展现状的基础上&#xff0c;结合金融行业用户的需求调研深入分析了…...

【k8s】k8s集群搭建

k8s集群搭建 一、环境准备1.1 集群类型1.2 安装方式1.3 主机规划1.4 环境配置1.4.1 说明1.4.2 初始化1.4.3 关闭防火墙和禁止防火墙开机启动1.4.4 设置主机名1.4.5 主机名解析1.4.6 时间同步1.4.7 关闭selinux1.4.8 关闭swap分区1.4.9 将桥接的IPv4流量传递到iptables的链1.4.1…...

60天python训练计划----day45

DAY 45 Tensorboard使用介绍 知识点回顾&#xff1a; tensorboard的发展历史和原理tensorboard的常见操作tensorboard在cifar上的实战&#xff1a;MLP和CNN模型 之前的内容中&#xff0c;我们在神经网络训练中&#xff0c;为了帮助自己理解&#xff0c;借用了很多的组件&#x…...

制作个人Github学术主页

1.fork一个模板 从模板网站Jekyll Themes fork一个模板&#xff0c;并在repository name里填入yourname.github.io 2.生成自己的site 按顺序点击以下按钮&#xff0c;修改Branch为master /root 然后点击save &#xff0c;等待一会后刷新&#xff0c;便会生成一个新的site。 3.…...

网关路由配置(Gateway Filters)

- id: system-admin-api # 路由的编号uri: grayLb://system-serverpredicates: # 断言&#xff0c;作为路由的匹配条件&#xff0c;对应 RouteDefinition 数组- Path/admin-api/system/**filters:- RewritePath/admin-api/system/v3/api-docs, /v3/api-docs # 配置&#xff0c;…...