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

news2024/11/27 13:15:34

一,中介者模式的定义

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

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

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

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

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

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

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

二,中介者模式的结构

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

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

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

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

相关文章

遗传算法与深度学习实战(12)——粒子群优化详解与实现

遗传算法与深度学习实战&#xff08;12&#xff09;——粒子群优化详解与实现 0. 前言1. 粒子群优化1.1 粒子群优化原理1.2 算法流程 2. 实现 PSO 解决方程2.1 问题描述2.2 代码实现 小结系列链接 0. 前言 粒子群优化 (Particle Swarm Optimization, PSO) 是一种借鉴适者生存和…

医疗行业怎么节约和管理能源

医院建筑能耗平台 医院智能照明平台 医院能源综合管理平台 目前&#xff0c;能源短缺已成为一个全球性问题。在建筑业的发展中&#xff0c;建筑电气照明系统的节能水平与中国的能源利用率有关。照明系统中的低功率因数和高电压波动将导致较大的功率损失。因此&#xff0c;要认…

计算机网络——ARP篇(二)

上一次学习了ARP的基本概念&#xff0c;ARP缓存&#xff0c;ARP类型&#xff0c;以及ARP协议在网络中是如何工作的。这一次&#xff0c;我又深入的了解了ARP协议的工作原理&#xff0c;下面是我的学习笔记&#xff1a; 在学习之前&#xff0c;首先提出三个问题&#xff1a;ARP协…

BizDevOps落地实践

我理解BizDevOps就是端到端&#xff0c;从战略业务机会到开发上线 参考资料 十六年所思所感&#xff0c;聊聊这些年我所经历的 DevOps 系统 必致&#xff08;BizDevOps&#xff09;白皮书2022免费下载_在线阅读_藏经阁-阿里云开发者社区 具体落地实践 战略规划 战略&…

C#使用TCP-S7协议读写西门子PLC(一)

之前本人发布西门子S7协议的报文 西门子PLC的S7协议报文解析说明_西门子报文详解-CSDN博客 西门子PLC的S7协议是西门子公司在ModbusTcp协议的基础上自定义的一种协议,仅支持西门子PLC,S7协议本质仍然属于TCP协议的一种自定义具体实现 第一步,准备工作。VS2022中新建窗体应…

动态规划及其MATLAB实现

目录 引言 动态规划的基本原理 动态规划的常见应用 动态规划的求解步骤 动态规划的复杂度分析 表格总结&#xff1a;动态规划常见问题及其复杂度 结论 引言 动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种求解最优化问题的有效方法&#xff0c;特别适合…

华为 HCIP-Datacom H12-821 题库 (16)

1.需要题库的小伙伴至博客最下方添加微信公众号关注后回复题库 2.有兴趣交流IT问题的小伙伴微信公众号回复交流群&#xff0c;加入微信IT交流群 1. OSPF 邻居关系建立出现故障&#xff0c;通过 display ospf error 命令来检查&#xff0c;输出结果如图所示&#xff0c;根据图中…

从零开始配置 TypeScript 项目

ESLint 配置 从背景的介绍中可以理解&#xff0c;对于全新的 TypeScript 项目&#xff08;直接抛弃 TSLint&#xff09;需要包含解析 AST 的解析器 typescript-eslint/parser 和使用校验规则的插件 typescript-eslint/eslint-plugin&#xff0c;这里需要在项目中进行安装&…

CentOS 安装Squid代理

环境&#xff1a; 华为云服务器一台&#xff1a;123.60.53.69&#xff0c;放行3128端口 Windows 11 电脑&#xff1a;动态IP 需求&#xff1a; 客户端电脑通过华为云服务器实现代理上网 一、服务器设置 1、安装 yum install squid httpd-tools -y 2、创建用户&#x…

word文档转换为PPT文档最佳方案

目前&#xff0c;笔者发现word文档转换为ppt最好的解决方案。 注&#xff1a;目前AI生成PPT&#xff0c;一般是给定一个标题&#xff0c;直接生成PPT文档内容&#xff0c;属于AI原创&#xff1b;另外&#xff0c;还有一些在线编辑、生成PPT工具&#xff0c;需要付费&#xff0c…

MySQL数据库SQL语句和常用函数大全

前言 MySQL 8数据库提供了丰富的SQL语句操作功能以及一系列高级特性&#xff0c;这些功能使得数据库的管理、查询、更新和维护变得更加高效和灵活。以下是对MySQL 8数据库SQL语句操作大全及高级特性的详细概述&#xff1a; 一、SQL语句操作大全 1. 数据定义语言&#xff08…

【雅特力AT32】 MCU CAN入门指南(超详细)

通信协议与接口知识参考文章&#xff1a; 【通信理论知识】数据传送的方式&#xff1a;串/并行&#xff1b;传输方向&#xff1a;单工、半/全双工&#xff1b;传输方式&#xff1a;同步/异步 【串口通信详解】USART/UART、RS232、RS485标准接口与协议特点解析 【同步串行通信接…

重拾精髓:go doc -http让离线包文档浏览更便捷

Go语言团队近期接受了Go团队成员、Go圣经《The Go Programming Language[1]》合著者Alan Donovan[2]的新提案[3]&#xff0c;旨在进一步提升开发者体验。这个提案为go doc命令[4]的离线文档展示形式&#xff0c;同时增强了查看本地文档的交叉引用功能。看到这个提案功能&#x…

重装电脑系统时硬盘被重新分区:数据恢复实战指南与深度解析

在数字化时代的浪潮中&#xff0c;电脑作为我们日常生活和工作的核心工具&#xff0c;其系统的稳定性与数据的完整性至关重要。然而&#xff0c;在追求系统性能优化或解决系统故障的过程中&#xff0c;重装电脑系统成为了一个常见的操作。不幸的是&#xff0c;这一过程中若不慎…

PB9一个运行时错误:Non-array expected in ANY Variable

反编译修改一个项目。遇到这个问题。 仿佛一看&#xff0c;这是一个莫名其妙的问题&#xff0c;在百度也只搜到一个类似问题。 但是定睛一看&#xff0c;是一个很奇怪的错误&#xff0c;就是说代码自己写错了 for i 1 to uo_1.is_arr ls_arrstr uo_1.is_arr[i] ... next …

掌握 JavaScript ES6+:现代编程技巧与模块化实践

掌握 JavaScript ES6&#xff1a;现代编程技巧与模块化实践 一 . 变量声明 let二 . 声明常量 const三 . 模板字符串四 . 函数的参数默认值五 . 箭头函数六 . 对象初始化七 . 解构7.1 接收 JSON 对象7.2 接收数组 八 . 延展操作符九 . 导入和导出9.1 方式一9.2 方式二 这篇文章我…

校篮球联赛系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;公告管理&#xff0c;基础数据管理&#xff0c;球队管理&#xff0c;球员管理&#xff0c;赛事信息管理&#xff0c;用户管理&#xff0c;轮播图信息 微信端账号功能包括&#…

文章解读与仿真程序复现思路——电网技术 EI\CSCD\北大核心《面向日前市场邀约的电动自行车换电站运行规划》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

聚观早报 | 2025款比亚迪汉上市;iPhone 16天猫全球同步首发

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 9月11日消息 2025款比亚迪汉上市 iPhone 16天猫全球同步首发 菜鸟L4级无人车正式发售 OPPO Find X8配置细节曝光…

DB33/T629 视频联网配置 USC安防平台

海康平台配置介绍 如下以海康ISC为例&#xff0c;配置DB33/T629接入流程。其中海康平台域标识为130101000020000099。DB33/T629 支持目录同步到usc。 DB33/T629服务配置 假设DB33/T629服务已经配置好&#xff0c;参考配置-》级联-》DB33/T629服务 DB33/T629下级域 进入配置-》…