设计模式15:中介者模式

 系列总链接:《大话设计模式》学习记录_net 大话设计-CSDN博客

1.概述

     中介者模式(Mediator Pattern)是一种行为设计模式,旨在通过一个中介对象来封装一系列对象之间的交互方式,从而减少这些对象间的直接依赖。在该模式下,各个组件(同事)不再直接相互通信,而是通过中介者进行间接沟通,这极大地降低了系统的耦合度。具体来说,中介者定义了同事类之间的通信接口,并负责协调同事对象之间的交互逻辑。每个同事类都知道其对应的中介者对象,但并不直接与其他同事类交互。

2.结构与实现

结构:

  • Mediator(抽象中介者):定义同事类之间的通信接口。
  • ConcreteMediator(具体中介者):实现了抽象中介者的接口,并协调各同事对象之间的交互。
  • Colleague Class(抽象同事类):每个同事类都知道其对应的中介者对象,并且可以通过中介者发送消息给其他同事。
  • ConcreteColleague(具体同事类):实现了抽象同事类,负责发送和接收消息。

实现:

假设我们要创建一个简单的聊天应用程序,用户之间通过ChatRoom(中介者)进行交流。

代码目录结构为:

首先,定义ChatRoom作为抽象中介者:

ChatRoom.h:

#ifndef CHATROOM_H
#define CHATROOM_H

#include <QString>

class User; // 前向声明User类,避免循环依赖

// 抽象中介者:定义同事类之间的通信接口。
class ChatRoom {
public:
    virtual void sendMessage(const QString& message, User* user) = 0; // 发送消息的纯虚函数
};

#endif // CHATROOM_H

ConcreteChatRoom.h

#ifndef CONCRETECHATROOM_H
#define CONCRETECHATROOM_H

#include "ChatRoom.h"
#include <QList> // Qt容器类,用于存储用户列表
#include "User.h"

// 具体中介者:实现了抽象中介者的接口,并协调各同事对象之间的交互。
class ConcreteChatRoom : public ChatRoom {
private:
    QList<User*> users; // 存储所有用户的列表
public:
    // 添加用户到聊天室中
    void addUser(User* user) {
        users.append(user);
    }

    // 实现发送消息的功能
    void sendMessage(const QString& message, User* user) override;
};

#endif // CONCRETECHATROOM_H

ConcreteChatRoom.cpp

#include "ConcreteChatRoom.h"
#include "User.h"
#include <QDebug>

// 实现sendMessage方法,遍历所有用户并转发消息给其他用户(除了发送者)
void ConcreteChatRoom::sendMessage(const QString& message, User* user)
{
    // 遍历所有用户
    for (User* u : users)
    {
        if(u != user) { // 如果不是消息的发送者,则转发消息
            u->receiveMessage(message); // 调用接收消息的方法
        }
    }
}

User.h

#ifndef USER_H
#define USER_H

#include <QString>
#include "ChatRoom.h" // 包含中介者接口

// 抽象同事类:每个同事类都知道其对应的中介者对象,并且可以通过中介者发送消息给其他同事。
class User {
protected:
    ChatRoom* chatroom; // 指向中介者的指针
    QString name; // 用户名
public:
    // 构造函数,初始化中介者和用户名
    User(ChatRoom* chatroom, const QString& name): chatroom(chatroom), name(name) {}

    // 发送消息的方法
    virtual void sendMessage(const QString& message);

    // 接收消息的方法
    virtual void receiveMessage(const QString& message);

    // 获取用户名的方法
    QString getName() const { return name; }
};

#endif // USER_H

User.cpp

#include "User.h"
#include "ConcreteChatRoom.h" // 包含具体中介者的头文件
#include <QDebug>

// 发送消息的实现
void User::sendMessage(const QString& message) {
    qDebug() << getName() << " sends: " << message; // 打印发送者信息
    chatroom->sendMessage(message, this); // 通过中介者发送消息
}

// 接收消息的实现
void User::receiveMessage(const QString& message) {
    qDebug() << getName() << " receives: " << message; // 打印接收者信息
}

main.cpp:

#include <QCoreApplication>
#include "ConcreteChatRoom.h" // 包含具体中介者
#include "User.h" // 包含同事类

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个具体的中介者实例
    ConcreteChatRoom chatRoom;

    // 创建两个用户并关联到同一个中介者
    User user1(&chatRoom, "Alice");
    User user2(&chatRoom, "Bob");
     User user3(&chatRoom, "Tom");

    // 将用户添加到聊天室中
    chatRoom.addUser(&user1);
    chatRoom.addUser(&user2);
    chatRoom.addUser(&user3);

    // 用户发送消息
    user1.sendMessage("Hello Bob!");
    //user2.sendMessage("Hi Alice!");

    return a.exec();
}

运行效果:

"Alice"  sends:  "Hello Bob!"
"Bob"  receives:  "Hello Bob!"
"Tom"  receives:  "Hello Bob!"

3.应用

中介者模式非常适合用于以下场景:

  • GUI框架中,例如Qt,其中各种控件可能需要相互通讯但又不希望直接依赖对方。
  • 多模块或分布式系统中,各个模块或节点之间的通信可以由中介者集中管理。
  • 状态管理器或控制器层,用于管理不同视图组件的状态更新和事件分发。

4.优缺点及适用环境

优点:

  • 减少依赖:减少了同事对象之间的直接依赖,降低了系统的耦合度。
  • 简化交互:通过中介者集中管理对象间的交互,使得代码更加清晰易读。
  • 易于扩展:新增同事对象时不需要修改现有的同事对象,只需调整中介者即可。

缺点:

  • 复杂性增加:如果中介者变得过于复杂,可能会成为系统的瓶颈,同时也会增加维护成本。
  • 单一职责原则:如果中介者承担过多的责任,可能会导致其变得庞大且难以管理。

应用环境:

  • 当系统中有大量对象需要相互通信,但你希望避免它们之间的直接引用时。
  • 对于那些希望通过引入中介者来提高模块独立性的系统来说,中介者模式是一个很好的选择。
  • 在开发复杂的GUI应用程序时,使用中介者模式可以帮助更好地管理和控制组件之间的交互。

      通过职责链模式,我们可以构建更加灵活、易于扩展的应用程序,尤其是在涉及多种类型的请求处理时。然而,在使用此模式时也应注意其可能带来的性能损耗和复杂性的增加。

5.举一反三

中介者模式因其能有效减少对象间的直接依赖和简化复杂的交互逻辑,适用于多种场景。以下是一些可以应用中介者模式的具体例子及其应用场景:

1. GUI应用程序

在Qt或其他GUI框架中,组件(如按钮、文本框等)之间的交互往往比较复杂。使用中介者模式可以帮助管理这些交互,避免组件间直接相互引用。

  • 示例:在一个表单中,某些输入框的可用性可能取决于其他输入框的内容或状态。例如,选择“是否需要发票”复选框后,相关的税号输入框才变为可编辑状态。通过引入一个中介者来监听这些事件并更新相应的UI组件状态,可以使代码更加清晰且易于维护。

2. 分布式系统中的模块通信

在分布式系统或微服务架构中,各个服务或模块之间需要进行通信。为了避免服务之间的直接依赖,可以通过引入中介者(如消息队列或API网关)来解耦这些服务。

  • 示例:在一个电商系统中,订单服务、库存服务和支付服务都需要相互通信以完成下单流程。使用中介者模式可以确保这些服务不直接相互调用,而是通过中介者传递消息,从而提高了系统的灵活性和可扩展性。

3. 游戏开发中的物体交互

在游戏中,不同游戏物体(如角色、敌人、道具等)之间的交互非常频繁。使用中介者模式可以帮助管理这些交互,特别是当涉及到多个物体同时对同一事件作出反应时。

  • 示例:在一个多人在线游戏中,当玩家捡起一件装备时,不仅该玩家的状态会发生变化,其他玩家也可能看到这一变化。通过引入一个中介者来协调这些状态更新,可以有效地管理复杂的同步逻辑。

4. 状态管理和事件分发

在具有复杂状态的应用程序中,比如企业级应用或大型网站,状态的变化可能会影响到多个视图或组件。使用中介者模式可以帮助集中管理这些状态变化,并通知相关联的视图或组件进行更新。

  • 示例:在一个具有多个视图的单页应用(SPA)中,用户登录状态的变化可能会影响导航栏、侧边栏等多个地方。通过使用中介者来处理这种状态变化,并向所有相关视图广播通知,可以使状态管理更加简洁高效。

5. 智能家居控制系统

智能家居设备(如灯光、温度控制器、安全系统等)通常需要根据环境变化或其他设备的状态自动调整其行为。使用中介者模式可以使得这些设备之间的交互更加灵活和独立。

  • 示例:当智能门锁检测到有人进入房屋时,它可以通过中介者通知室内照明系统开启特定区域的灯光,并告知温控器调整室温。这种方式既实现了设备间的解耦,又保证了响应的及时性和准确性。

总之,中介者模式非常适合用于那些需要管理多个对象间复杂交互的场景,特别是在希望减少对象间直接依赖、提高模块独立性以及简化交互逻辑的情况下。通过合理地应用中介者模式,可以构建出更加灵活、易于维护和扩展的软件系统。

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

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

相关文章

爬取网站内容转为markdown 和 html(通常模式)

我们遇到一些自己喜欢内容&#xff0c;想保存下来&#xff0c;手动复制粘贴很麻烦&#xff0c;我们使用 python 来爬取这些内容。 一、代码 downlod.py import os import requests from bs4 import BeautifulSoup from urllib.parse import urljoin# 目标网页&#xff08;可…

【Linux】命令操作、打jar包、项目部署

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;Xshell下载 1&#xff1a;镜像设置 二&#xff1a;阿里云设置镜像Ubuntu 三&#xf…

Unity合批处理优化内存序列帧播放动画

Unity合批处理序列帧优化内存 介绍图片导入到Unity中的处理Unity中图片设置处理Unity中图片裁剪 创建序列帧动画总结 介绍 这里是针对Unity序列帧动画的优化内容&#xff0c;将多个图片合批处理然后为了降低Unity的内存占用&#xff0c;但是相对的质量也会稍微降低。可自行进行…

day4 多连联表慢查询sql查询优化

1.Explain分析sql语句出现的字段是什么意思 id: 查询的序列号&#xff0c;表示查询中 select 子句或操作表的顺序。 如果 id 相同&#xff0c;则执行顺序从上到下。 如果 id 不同&#xff0c;如果是子查询&#xff0c;id 的值会递增&#xff0c;id 值越大优先级越高&#xff0c…

基于豆瓣2025电影数据可视化分析系统的设计与实现

✔️本项目旨在通过对豆瓣电影数据进行综合分析与可视化展示&#xff0c;构建一个基于Python的大数据可视化系统。通过数据爬取收集、清洗、分析豆瓣电影数据&#xff0c;我们提供了一个全面的电影信息平台&#xff0c;为用户提供深入了解电影产业趋势、影片评价与演员表现的工…

力扣高频sql 50题(基础版) :NULL, 表连接,子查询,case when和avg的结合

NULL的处理 nvl(字段,num) 和数字进行比较需要先使用nvl(字段,num)函数处理空值 思路: 没有被id 2 的客户推荐>> 过滤条件 referee_id !2 没有被id 2 的客户推荐>>被其他客户推荐, 但是也有可能没有被任何客户推荐>>NULL 考点: NULL是 不一个具体的数…

夜莺监控发布 v8.beta5 版本,优化 UI,新增接口认证方式便于鉴权

以防读者不了解夜莺&#xff0c;开头先做个介绍&#xff1a; 夜莺监控&#xff0c;英文名字 Nightingale&#xff0c;是一款侧重告警的监控类开源项目。类似 Grafana 的数据源集成方式&#xff0c;夜莺也是对接多种既有的数据源&#xff0c;不过 Grafana 侧重在可视化&#xff…

Python - 爬虫利器 - BeautifulSoup4常用 API

文章目录 前言BeautifulSoup4 简介主要特点&#xff1a;安装方式: 常用 API1. 创建 BeautifulSoup 对象2. 查找标签find(): 返回匹配的第一个元素find_all(): 返回所有匹配的元素列表select_one() & select(): CSS 选择器 3. 访问标签内容text 属性: 获取标签内纯文本get_t…

认识 ADB(Android Debug Bridge,Android SDK 中的一个工具)

一、ADB 概述 ADB&#xff0c;全称 Android Debug Bridge&#xff0c;是 Android SDK 中的一个工具 ADB 位于 Android SDK 下 platform-tools 目录中 ADB 起到调试桥的作用&#xff0c;ADB 可以让开发者通过 USB 连接安卓设备&#xff0c;并在电脑上执行各种命令&#xff0c;…

模拟解决哈希表冲突

目录 解决哈希表冲突原理&#xff1a; 模拟解决哈希表冲突代码&#xff1a; 负载因子&#xff1a; 动态扩容&#xff1a; 总结&#xff1a; HashMap和HashSet的总结&#xff1a; 解决哈希表冲突原理&#xff1a; 黑色代表一个数组&#xff0c;当 出现哈希冲突时&#xff0…

FPGA简介|结构、组成和应用

Field Programmable Gate Arrays&#xff08;FPGA&#xff0c;现场可编程逻辑门阵列&#xff09;&#xff0c;是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物&#xff0c; 是作为专用集成电路&#xff08;ASIC&#xff09;领域中的一种半定制电路而出现的&#xff0c…

【机器学习】超参数调优指南:交叉验证,网格搜索,混淆矩阵——基于鸢尾花与数字识别案例的深度解析

一、前言&#xff1a;为何要学交叉验证与网格搜索&#xff1f; 大家好&#xff01;在机器学习的道路上&#xff0c;我们经常面临一个难题&#xff1a;模型调参。比如在 KNN 算法中&#xff0c;选择多少个邻居&#xff08;n_neighbors&#xff09;直接影响预测效果。 • 蛮力猜…

UGUI RectTransform的SizeDelta属性

根据已知内容&#xff0c;SizeDelta offsetMax - offsetMin 1.锚点聚拢情况下 输出 那么此时SizeDelta就是UI元素的长宽大小 2. 锚点分散时 引用自此篇文章中的描述 揭秘&#xff01;anchoredPosition的几何意义&#xff01; SizeDelta offsetMax - offsetMin (rectMax…

51单片机入门_10_数码管动态显示(数字的使用;简单动态显示;指定值的数码管动态显示)

接上篇的数码管静态显示&#xff0c;以下是接上篇介绍到的动态显示的原理。 动态显示的特点是将所有位数码管的段选线并联在一起&#xff0c;由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选&#xff…

mybatis使用typeHandler实现类型转换

使用mybatis作为操作数据库的orm框架&#xff0c;操作基本数据类型时可以通过内置的类型处理器完成java数据类型和数据库类型的转换&#xff0c;但是对于扩展的数据类型要实现与数据库类型的转换就需要自定义类型转换器完成&#xff0c;比如某个实体类型存储到数据库&#xff0…

瑞萨RA-T系列芯片ADCGPT功能模块的配合使用

在马达或电源工程中&#xff0c;往往需要采集多路AD信号&#xff0c;且这些信号的优先级和采样时机不相同。本篇介绍在使用RA-T系列芯片建立马达或电源工程时&#xff0c;如何根据需求来设置主要功能模块ADC&GPT&#xff0c;包括采样通道打包和分组&#xff0c;GPT触发启动…

最新智能优化算法:牛优化( Ox Optimizer,OX)算法求解经典23个函数测试集,MATLAB代码

一、牛优化算法 牛优化&#xff08; OX Optimizer&#xff0c;OX&#xff09;算法由 AhmadK.AlHwaitat 与 andHussamN.Fakhouri于2024年提出&#xff0c;该算法的设计灵感来源于公牛的行为特性。公牛以其巨大的力量而闻名&#xff0c;能够承载沉重的负担并进行远距离运输。这种…

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用

【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用 文章目录 【linux】在 Linux 服务器上部署 DeepSeek-r1:70b 并通过 Windows 远程可视化使用个人配置详情一、安装ollama二、下载deepseek版本模型三、在 Linux 服务器上配置 Ollama 以允许远程访…

【Linux网络编程】应用层协议HTTP(请求方法,状态码,重定向,cookie,session)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux网络编程笔记&#xff1a; https://blog.cs…

Chrome多开终极形态解锁!「窗口管理工具+IP隔离插件

Web3项目多开&#xff0c;继ads指纹浏览器钱包被盗后&#xff0c;更多人采用原生chrome浏览器&#xff0c;当然对于新手&#xff0c;指纹浏览器每月成本也是一笔不小开支&#xff0c;今天逛Github发现了这样一个解决方案&#xff0c;作者开发了窗口管理工具IP隔离插件&#xff…