设计模式15:中介者模式

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

1.概述

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

2.结构与实现

结构:

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

实现:

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

代码目录结构为:

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

ChatRoom.h:

cpp 复制代码
#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

cpp 复制代码
#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

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

cpp 复制代码
#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

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:

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();
}

运行效果:

bash 复制代码
"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. 智能家居控制系统

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

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

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

相关推荐
令狐掌门22 分钟前
C++中间件DDS介绍
c++·中间件·c++ dds
专注VB编程开发20年6 小时前
除了 EasyXLS,加载和显示.xlsx 格式的excel表格,并支持单元格背景色、边框线颜色和粗细等格式化特性
c++·windows·excel·mfc·xlsx
夏天的阳光吖7 小时前
C++蓝桥杯基础篇(四)
开发语言·c++·蓝桥杯
oioihoii7 小时前
C++17 中的 std::to_chars 和 std::from_chars:高效且安全的字符串转换工具
开发语言·c++
张胤尘7 小时前
C/C++ | 每日一练 (2)
c语言·c++·面试
付聪12108 小时前
装饰器模式
设计模式
扣丁梦想家8 小时前
设计模式教程:外观模式(Facade Pattern)
设计模式·外观模式
強云8 小时前
23种设计模式 - 装饰器模式
c++·设计模式·装饰器模式
強云8 小时前
23种设计模式 - 外观模式
设计模式·外观模式
yatingliu20198 小时前
代码随想录算法训练营第六天| 242.有效的字母异位词 、349. 两个数组的交集、202. 快乐数 、1. 两数之和
c++·算法