C++软件设计模式之中介者模式

中介者模式(Mediator Pattern)是一种行为设计模式,它的主要目的是通过引入一个中介者对象来简化多个对象之间的交互,降低它们之间的耦合度。中介者模式使得这些对象可以通过中介者进行通信,而不需要直接相互引用,从而使得系统更加灵活和易于维护。

目的和意图

目的

  • 减少对象之间的直接耦合:通过中介者对象来协调多个对象之间的交互,使得这些对象不需要直接引用彼此。
  • 简化对象间的通信:对象只需要与中介者通信,而不需要知道其他对象的存在或如何与它们交互。
  • 集中管理交互逻辑:将多个对象之间的交互逻辑集中到中介者中,使得交互逻辑更容易理解和管理。

意图

  • 定义一个中介对象:中介者对象封装了对象之间的交互,使得对象之间的交互变得松散耦合。
  • 促进松耦合:通过中介者,对象只与中介者耦合,而不是与多个其他对象耦合。
  • 支持可扩展性:新的对象可以更容易地添加到系统中,而不需要修改现有的对象,只要它们与中介者进行交互。

适用场合

  1. 对象之间有复杂的引用关系:当系统中的对象之间存在复杂的引用关系,导致难以理解或维护时,可以使用中介者模式来简化这些关系。
  2. 需要控制对象之间的交互:当需要集中控制对象之间的交互逻辑时,中介者模式可以提供一个集中的地方来管理这些交互。
  3. 希望复用控制逻辑:如果多个场景需要类似的交互控制逻辑,可以将这些逻辑集中到中介者中,从而实现代码的复用。
  4. 对象间交互多变:当对象之间的交互可能随着需求的变化而变化时,中介者模式可以使得这些变化更容易管理。

中介者模式与外观模式的比较

相似点

  1. 抽象-layering:两者都旨在提供一个更高层次的抽象来简化与系统中一组对象的交互。
  2. 减少直接耦合:两者都试图减少系统中对象之间的直接耦合,通过引入一个新的对象来处理交互。

本质不同

  1. 目的不同

    • 中介者模式:主要目的是将多个对象之间的复杂交互逻辑集中到一个中介者对象中,以降低对象之间的耦合度,并使交互逻辑更易于管理和维护。
    • 外观模式:主要目的是为子系统提供一个简化的接口,使得子系统的使用变得更加简单和直接,从而降低系统的复杂度。
  2. 角色不同

    • 中介者模式:包含中介者(Mediator)和同事(Colleague)对象,同事对象通过中介者进行交互。
    • 外观模式:包含外观(Facade)和子系统(Subsystem)对象,外观对象提供了一个统一的接口来与子系统交互。
  3. 关注点不同

    • 中介者模式:关注于如何管理对象之间的交互,强调交互逻辑的集中管理。
    • 外观模式:关注于如何简化子系统的接口,提供一个更易于使用的入口。

C++示例代码

以下是一个简单的C++示例,展示了中介者模式的应用。

场景

假设我们有一个简单的论坛系统,其中有多名用户可以发布帖子和回复。每个用户对象需要与其它用户交互,例如发送消息或接收消息。为了避免用户对象之间直接引用,我们可以引入一个中介者对象来管理这些交互。

实现

  1. 定义中介者接口

    class Mediator {
    public:
        virtual void send(const std::string& message, User* user) = 0;
        virtual ~Mediator() {}
    };
    
  2. 具体中介者类

    class ChatRoom : public Mediator {
    public:
        void send(const std::string& message, User* user) override {
            for (auto& u : users) {
                if (u != user) {
                    u->receive(message);
                }
            }
        }
    
        void addUser(User* user) {
            users.push_back(user);
        }
    
    private:
        std::vector<User*> users;
    };
    
  3. 定义同事类

    class User {
    public:
        User(Mediator* mediator, const std::string& name)
            : mediator(mediator), name(name) {}
    
        void send(const std::string& message) {
            mediator->send(message, this);
        }
    
        void receive(const std::string& message) {
            std::cout << name << " received message: " << message << std::endl;
        }
    
    private:
        Mediator* mediator;
        std::string name;
    };
    
  4. 客户端代码

    int main() {
        ChatRoom chatRoom;
        User user1(&chatRoom, "Alice");
        User user2(&chatRoom, "Bob");
    
        chatRoom.addUser(&user1);
        chatRoom.addUser(&user2);
    
        user1.send("Hi Bob!");
        user2.send("Hello Alice!");
    
        return 0;
    }
    

代码解释

  • Mediator 接口:定义了发送消息的方法。
  • ChatRoom 类:实现了 Mediator 接口,管理用户列表,并负责将消息分发给除了发送者之外的其他用户。
  • User 类:用户类,通过中介者发送和接收消息。
  • main 函数:创建 ChatRoom 和 User 对象,演示用户之间通过中介者发送消息。

通过这种方式,用户对象之间没有直接引用,而是通过中介者进行交互,从而降低了耦合度,使得系统更易于扩展和维护。

中介者模式(Mediator Pattern)经常与其他设计模式协同使用,以解决更复杂的设计问题。以下是几种常见的协同使用模式及其示例:

1. 中介者模式与观察者模式

目的

  • 中介者模式:管理对象之间的交互,集中交互逻辑。
  • 观察者模式:定义对象间的一对多依赖,当一个对象状态改变时,所有依赖它的对象都会收到通知。

适用场景

当系统中对象之间的交互不仅需要集中管理,而且需要在特定事件发生时通知多个对象时,可以结合使用中介者模式和观察者模式。

示例代码

假设我们有一个简单的股票交易系统,其中有多名交易员和多个股票。交易员可以订阅特定股票的报价,并在股票价格变化时收到通知。

#include <iostream>
#include <vector>
#include <string>

// 抽象中介者
class Mediator {
public:
    virtual void subscribe(const std::string& stock, Observer* observer) = 0;
    virtual void notify(const std::string& stock, double price) = 0;
    virtual ~Mediator() {}
};

// 具体中介者
class StockExchange : public Mediator {
public:
    void subscribe(const std::string& stock, Observer* observer) override {
        observers[stock].push_back(observer);
    }

    void notify(const std::string& stock, double price) override {
        for (auto observer : observers[stock]) {
            observer->update(stock, price);
        }
    }

private:
    std::map<std::string, std::vector<Observer*>> observers;
};

// 观察者接口
class Observer {
public:
    virtual void update(const std::string& stock, double price) = 0;
    virtual ~Observer() {}
};

// 具体观察者:交易员
class Trader : public Observer {
public:
    Trader(const std::string& name) : name(name) {}

    void update(const std::string& stock, double price) override {
        std::cout << name << " received update: " << stock << " price is " << price << std::endl;
    }

private:
    std::string name;
};

int main() {
    StockExchange exchange;

    Trader trader1("Alice");
    Trader trader2("Bob");

    exchange.subscribe("AAPL", &trader1);
    exchange.subscribe("GOOGL", &trader2);
    exchange.subscribe("AAPL", &trader2);

    exchange.notify("AAPL", 150.0);
    exchange.notify("GOOGL", 2500.0);

    return 0;
}

解释

  • Mediator 接口:定义了订阅和通知的方法。
  • StockExchange 类:实现了 Mediator 接口,管理观察者订阅和通知。
  • Observer 接口:定义了更新方法。
  • Trader 类:具体观察者,实现更新方法以接收股票价格变化通知。
  • main 函数:创建 StockExchange 和 Trader 对象,演示交易员订阅股票并接收价格更新。

2. 中介者模式与策略模式

目的

  • 中介者模式:管理对象之间的交互。
  • 策略模式:定义一系列算法,封装起来,使其可以互换。

适用场景

当中介者需要根据不同的策略来处理对象之间的交互时,可以结合使用中介者模式和策略模式。

示例代码

假设我们有一个简单的任务分配系统,其中管理员可以分配任务给不同的员工,员工根据他们的能力和当前负荷来接受任务。管理员可以根据不同的策略来分配任务,例如基于员工的空闲时间或技能水平。

#include <iostream>
#include <vector>
#include <string>

// 策略接口
class AllocationStrategy {
public:
    virtual Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) = 0;
    virtual ~AllocationStrategy() {}
};

// 具体策略:基于空闲时间
class ByIdleTime : public AllocationStrategy {
public:
    Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) override {
        Employee* selected = nullptr;
        int maxIdleTime = -1;
        for (Employee* emp : employees) {
            if (emp->idleTime > maxIdleTime) {
                selected = emp;
                maxIdleTime = emp->idleTime;
            }
        }
        return selected;
    }
};

// 具体策略:基于技能水平
class BySkillLevel : public AllocationStrategy {
public:
    Employee* allocateTask(const Task& task, const std::vector<Employee*>& employees) override {
        for (Employee* emp : employees) {
            if (emp->skills.find(task.requiredSkill) != emp->skills.end()) {
                return emp;
            }
        }
        return nullptr;
    }
};

// 抽象中介者
class Mediator {
public:
    virtual void setAllocationStrategy(AllocationStrategy* strategy) = 0;
    virtual void assignTask(const Task& task) = 0;
    virtual ~Mediator() {}
};

// 具体中介者
class TaskAllocator : public Mediator {
public:
    void setAllocationStrategy(AllocationStrategy* strategy) override {
        this->strategy = strategy;
    }

    void assignTask(const Task& task) override {
        Employee* selected = strategy->allocateTask(task, employees);
        if (selected) {
            selected->acceptTask(task);
        } else {
            std::cout << "No suitable employee found for task: " << task.description << std::endl;
        }
    }

    void addEmployee(Employee* employee) {
        employees.push_back(employee);
    }

private:
    AllocationStrategy* strategy;
    std::vector<Employee*> employees;
};

// 员工类
class Employee {
public:
    Employee(const std::string& name, int idleTime, const std::set<std::string>& skills)
        : name(name), idleTime(idleTime), skills(skills) {}

    void acceptTask(const Task& task) {
        std::cout << name << " accepted task: " < < task.description << std::endl;
    }

private:
    std::string name;
    int idleTime;
    std::set<std::string> skills;
};

// 任务类
class Task {
public:
    Task(const std::string& desc, const std::string& skill)
        : description(desc), requiredSkill(skill) {}

    std::string description;
    std::string requiredSkill;
};

int main() {
    TaskAllocator allocator;

    Employee emp1("Alice", 5, {"C++", "Python"});
    Employee emp2("Bob", 3, {"Python", "Java"});

    allocator.addEmployee(&emp1);
    allocator.addEmployee(&emp2);

    // 使用基于空闲时间的策略
    allocator.setAllocationStrategy(new ByIdleTime());
    Task task1("Develop new feature", "C++");
    allocator.assignTask(task1);

    // 使用基于技能水平的策略
    allocator.setAllocationStrategy(new BySkillLevel());
    Task task2("Fix bug", "Python");
    allocator.assignTask(task2);

    return 0;
}

解释

  • AllocationStrategy 接口:定义了任务分配策略。
  • ByIdleTime 和 BySkillLevel 类:具体策略,根据空闲时间和技能水平分配任务。
  • Mediator 接口:定义了设置策略和分配任务的方法。
  • TaskAllocator 类:实现了 Mediator 接口,管理员工列表和任务分配。
  • Employee 类:员工类,接受任务并处理。
  • Task 类:任务类,包含描述和所需技能。
  • main 函数:创建 TaskAllocator 和 Employee 对象,演示不同策略下的任务分配。

通过这种方式,中介者模式和策略模式结合使用,使得任务分配的逻辑既集中管理,又可以根据不同的策略灵活变化。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提升口语发音水平,中英文发音评测系统实现

在全球化的浪潮中&#xff0c;语言不再是障碍&#xff0c;而是连接世界的桥梁。掌握一门流利的英语&#xff0c;意味着打开了通往世界的大门。但是&#xff0c;如何确保你的英语口语如同母语者一样自然流畅&#xff1f;这正是我们存在的意义。 我们的中英文口语发音评测服务&a…

C语言初阶习题【20】扫雷游戏

1.用C语言实现扫雷游戏 本博客和三子棋游戏比较大的区别是&#xff0c;三子棋游戏是写完了再总结的&#xff0c;本博客是边代码实现边编辑博客&#xff0c;所以本博客会比较详细的po出每一步骤&#xff0c;在每实现一个小功能的时候我们都先验证下效果&#xff0c;再继续下一步…

Python AI教程之七:多项式回归

多项式回归的实现 多项式回归是一种线性回归,其中独立变量 x 和因变量 y 之间的关系被建模为n 次多项式。多项式回归拟合 x 的值与 y 的相应条件均值之间的非线性关系,表示为 E(y | x)。在本文中,我们将深入探讨多项式回归。 目录 什么是多项式回归? 为什么采用多项式回归…

【Leetcode】3280. 将日期转换为二进制表示

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个字符串 date&#xff0c;它的格式为 yyyy-mm-dd&#xff0c;表示一个公历日期。 date 可以重写为二进制表示&#xff0c;只需要将年、月、日分别转换为对应的二进制表示&a…

网段划分和 IP 地址

1. IP 协议 IP 协议是网络层协议&#xff0c;主要负责在不同网络设备之间&#xff0c;进行数据包的地址分配和路由选择。 地址分配&#xff1a;为每个连接到公网的设备分配一个唯一的 IP 地址&#xff0c;确保数据能被准确地发送到目标设备。 数据分片和组装&#xff1a;当发…

【Python系列】Python 中对对象列表进行排序

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

微服务のGeteWay

目录 概念&#xff1a; 三大核心&#xff1a; 工作流程&#xff1a; 9527网关如何做路由映射&#xff1a; GetWay高级特性&#xff1a; 按服务名动态路由服务&#xff1a; 断言Route Predicate Factories &#xff1a; 获取当前时区时间&#xff1a; After Route &…

数字图像处理 三 空间滤波

空间滤波是一种图像处理技术&#xff0c;它通过对图像像素及其邻域进行运算&#xff0c;利用均值&#xff0c;高斯&#xff0c;梯度&#xff0c;拉普拉斯等线性滤波和中值&#xff0c;最大最小&#xff0c;双边滤波等非线性滤波改变像素值&#xff0c;实现图像的平滑&#xff0…

【CVE-2024-12987 】DrayTek 网关设备中 `apmcfgupload` 端点的命令注入漏洞

概述 DrayTek 网关设备(包括 Vigor2960 和 Vigor300B 型号)存在通过 Web 管理接口进行命令注入的漏洞。攻击者可以通过发送恶意的 HTTP 请求到 /cgi-bin/mainfunction.cgi/apmcfgupload 端点,利用该漏洞注入任意命令,从而影响超过 66,000 台连接到互联网的设备。 受影响的…

mac下载Homebrew安装nvm

通过Homebrew安装 - 国内下载地址 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"安装nvm brew install nvm 配置nvm环境变量 export NVM_DIR“$HOME/.nvm” [ -s “/usr/local/opt/nvm/nvm.sh” ] && . “/usr/…

[react] 纯组件优化子

有组件如下,上面变化秒数, 下面是大量计算的子组件,上面每一秒钟变化一次,这时候子组件会不断重新渲染, 浪费资源 父组件如下 import React, { memo, useEffect, useMemo, useState } from react; import type { ReactNode, FC } from react; import HugeCount from ./Te; int…

Unity Mesh生成Cube

1. 配置一个Cube的每个面的数据 一共是6个面&#xff0c;每个面包含的数据包括4个顶点的相对顶点坐标&#xff08;Cube的中心为原点&#xff09;&#xff0c;法线方向&#xff0c;UV坐标&#xff0c;顶点渲染顺序&#xff0c;以及这个面用到的材质&#xff0c;因为这里是Top&am…

Spring--三级缓存机制

一、什么是三级缓存 就是在Bean生成流程中保存Bean对象三种形态的三个Map集合&#xff0c;如下&#xff1a; // 一级缓存Map 存放完整的Bean&#xff08;流程跑完的&#xff09; private final Map<String, Object> singletonObjects new ConcurrentHashMap(256);// 二…

使用R语言绘制标准的中国地图和世界地图

在日常的学习和生活中&#xff0c;有时我们常常需要制作带有国界线的地图。这个时候绘制标准的国家地图就显得很重要。目前国家标准地图服务系统向全社会公布的标准中国地图数据&#xff0c;是最权威的地图数据。 今天介绍的R包“ggmapcn”&#xff0c;就是基于最新公布的地图…

2025考研江南大学复试科目控制综合(初试807自动控制原理)

​ 2025年全国硕士研究生招生考试江南大学考点 一年年的考研如期而至&#xff0c;我也变成了研二了&#xff0c;作为2次考研经历的学长&#xff0c;总是情不自禁地回想起自己的考研经历&#xff0c;我也会经常从那段经历中汲取力量。我能理解大多数考生考完后的的迷茫无助&…

WebApi使用 (.Net Framework版)

1 创建 使用.Net做web后端&#xff0c;推荐使用.Net Core&#xff0c;微软在此基础上做了很多适配&#xff0c;包括内置Swagger&#xff0c;可以直接启动等等。而.Net Framework版&#xff0c;需要手动配置很多内容。 如果需要调用的项目是基于.Net Framework&#xff0c;那么…

使用 ASP.NET Core wwwroot 上传和存储文件

在 ASP.NET Core 应用程序中上传和存储文件是用户个人资料、产品目录等功能的常见要求。本指南将解释使用wwwroot存储图像&#xff08;可用于文件&#xff09;的过程以及如何在应用程序中处理图像上传。 步骤 1&#xff1a;设置项目环境 确保您的 ASP.NET 项目中具有必要的依…

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)

概述 在国家政策的强力扶持下&#xff0c;2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告&#xff08;2024年&#xff09;》的数据&#xff0c;对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动&#xff1a;国家和地…

[论文粗读]A Simple Framework for Contrastive Learning of Visual Representations

引言 今天带来一篇经典论文A Simple Framework for Contrastive Learning of Visual Representations的笔记。 本篇工作提出了SimCLR&#xff0c;一种用于视觉表征对比学习的简单框架。提出(1)数据增强组合在定义有效预测任务中起到至关重要的作用&#xff1b;(2)在表示和对比…

(leetcode算法题)188. 买卖股票的最佳时机 IV

题目中要求最多可以完成k次交易&#xff0c;很多时候不要把问题搞复杂了&#xff0c; 按照题目要求&#xff0c;研究对象是最后一天结束后最多进行了 k 次交易获得的最大利润 那么就可以把问题拆分成 第 1 天结束后完成 0 次交易获得的最大利润&#xff0c;第 1 天结束后完成…