17.C++设计模式-中介者模式

第一部分:模式基础详解

1. 模式概述

中介者模式(Mediator Pattern)是一种行为设计模式,通过引入一个中介对象来封装一组对象之间的交互。中介者使各对象不需要显式地相互引用,从而降低耦合度,并可以独立地改变它们之间的交互。

2. 核心角色

«interface»

Mediator

+notify(sender, event)

ConcreteMediator

-colleague1

-colleague2

+notify(sender, event)

«abstract»

Colleague

-mediator

+setMediator(mediator)

+send(event)

+receive(event)

ConcreteColleagueA

+receive(event)

ConcreteColleagueB

+receive(event)

3. 应用场景

  • 聊天室系统:用户通过聊天室发送和接收消息
  • 航空管制系统:塔台协调飞机起降
  • GUI组件交互:按钮、文本框、下拉框等组件的联动
  • 表单验证:多个表单字段的相互依赖验证
  • 工作流引擎:协调多个任务节点

4. C++代码示例

场景:智能家居控制系统

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

// 前向声明
class Colleague;

// 中介者接口
class Mediator {
public:
    virtual ~Mediator() = default;
    virtual void notify(const std::string& sender, const std::string& event) = 0;
};

// 抽象同事类
class Colleague {
protected:
    std::shared_ptr<Mediator> mediator;
    std::string name;
    
public:
    Colleague(const std::string& n) : name(n) {}
    
    void setMediator(std::shared_ptr<Mediator> m) {
        mediator = m;
    }
    
    virtual void send(const std::string& event) {
        if (mediator) {
            mediator->notify(name, event);
        }
    }
    
    virtual void receive(const std::string& event) = 0;
    
    std::string getName() const { return name; }
    virtual ~Colleague() = default;
};

// 具体同事类:灯
class Light : public Colleague {
private:
    bool isOn = false;
    
public:
    Light(const std::string& n) : Colleague(n) {}
    
    void receive(const std::string& event) override {
        if (event == "turn_on") {
            isOn = true;
            std::cout << name << " 已打开" << std::endl;
        } else if (event == "turn_off") {
            isOn = false;
            std::cout << name << " 已关闭" << std::endl;
        }
    }
    
    bool getStatus() const { return isOn; }
};

// 具体同事类:空调
class AirConditioner : public Colleague {
private:
    int temperature = 22;
    
public:
    AirConditioner(const std::string& n) : Colleague(n) {}
    
    void receive(const std::string& event) override {
        if (event == "turn_on") {
            std::cout << name << " 已打开,当前温度:" << temperature << "°C" << std::endl;
        } else if (event == "turn_off") {
            std::cout << name << " 已关闭" << std::endl;
        } else if (event.substr(0, 12) == "set_temp_to_") {
            temperature = std::stoi(event.substr(12));
            std::cout << name << " 温度设置为:" << temperature << "°C" << std::endl;
        }
    }
};

// 具体同事类:智能音箱
class SmartSpeaker : public Colleague {
public:
    SmartSpeaker(const std::string& n) : Colleague(n) {}
    
    void receive(const std::string& event) override {
        if (event == "play_music") {
            std::cout << name << " 开始播放音乐" << std::endl;
        } else if (event == "stop_music") {
            std::cout << name << " 停止播放音乐" << std::endl;
        } else if (event == "weather_report") {
            std::cout << name << " 播报天气:晴天,25°C" << std::endl;
        }
    }
};

// 具体中介者:智能家居控制中心
class SmartHomeHub : public Mediator, public std::enable_shared_from_this<SmartHomeHub> {
private:
    std::vector<std::shared_ptr<Colleague>> devices;
    
public:
    void addDevice(std::shared_ptr<Colleague> device) {
        devices.push_back(device);
        device->setMediator(shared_from_this());
    }
    
    void notify(const std::string& sender, const std::string& event) override {
        std::cout << "\n[智能家居中心] 收到来自 " << sender << " 的事件: " << event << std::endl;
        
        if (event == "good_morning") {
            // 早安模式:开灯、设置空调温度、播放新闻
            for (auto& device : devices) {
                if (device->getName() == "客厅灯") {
                    device->receive("turn_on");
                } else if (device->getName() == "空调") {
                    device->receive("turn_on");
                    device->receive("set_temp_to_24");
                } else if (device->getName() == "智能音箱") {
                    device->receive("weather_report");
                }
            }
        } 
        else if (event == "good_night") {
            // 晚安模式:关灯、关空调、停止音乐
            for (auto& device : devices) {
                if (device->getName() == "客厅灯" || device->getName() == "卧室灯") {
                    device->receive("turn_off");
                } else if (device->getName() == "空调") {
                    device->receive("turn_off");
                } else if (device->getName() == "智能音箱") {
                    device->receive("stop_music");
                }
            }
        }
        else if (event == "leave_home") {
            // 离家模式:关闭所有设备
            for (auto& device : devices) {
                device->receive("turn_off");
            }
        }
        else if (event == "light_on") {
            // 特定设备控制
            for (auto& device : devices) {
                if (device->getName() == "客厅灯") {
                    device->receive("turn_on");
                }
            }
        }
    }
};

// 客户端代码
int main() {
    // 创建中介者
    auto hub = std::make_shared<SmartHomeHub>();
    
    // 创建设备
    auto livingLight = std::make_shared<Light>("客厅灯");
    auto bedroomLight = std::make_shared<Light>("卧室灯");
    auto ac = std::make_shared<AirConditioner>("空调");
    auto speaker = std::make_shared<SmartSpeaker>("智能音箱");
    
    // 注册设备到中介者
    hub->addDevice(livingLight);
    hub->addDevice(bedroomLight);
    hub->addDevice(ac);
    hub->addDevice(speaker);
    
    // 设备通过中介者通信
    std::cout << "=== 早安模式 ===" << std::endl;
    speaker->send("good_morning");
    
    std::cout << "\n=== 离家模式 ===" << std::endl;
    speaker->send("leave_home");
    
    std::cout << "\n=== 单独控制灯光 ===" << std::endl;
    livingLight->send("light_on");
    
    return 0;
}

5. 交互流程图

空调客厅灯智能家居中心智能音箱空调客厅灯智能家居中心智能音箱协调完成所有操作send("good_morning")receive("turn_on")执行完成receive("turn_on")receive("set_temp_to_24")执行完成

6. 优缺点分析

优点:

  • ✅ 降低对象间耦合,提高可维护性
  • ✅ 集中控制交互逻辑,便于修改
  • ✅ 符合迪米特法则(最少知识原则)
  • ✅ 提高组件复用性

缺点:

  • ❌ 中介者可能变得庞大复杂(上帝对象)
  • ❌ 增加系统复杂度(需要额外的中介者对象)
  • ❌ 调试困难(交互集中在中介者)

7. 与其他模式对比

模式适用场景复杂度
中介者多对象网状交互
观察者一对多依赖通知
外观简化复杂子系统接口

第二部分:核心思想思维深度讲解

1. 思维的本质转变

中介者模式最核心的思维转变是:从“对象知道对象”到“对象只知中介”

中介者模式(星型结构)

对象A

中介者

对象B

对象C

对象D

传统网状交互(高耦合)

对象A

对象B

对象C

对象D

2. 四个关键思维转变

思维一:从“知道太多”到“只知必要”

// ❌ 坏味道:对象知道太多其他对象
class BadLight {
    AirConditioner* ac;
    Speaker* speaker;
    Curtain* curtain;
    
    void morningMode() {
        ac->turnOn(24);
        speaker->play("news");
        curtain->open();
        this->turnOn();
    }
};

// ✅ 中介者思维:只知道中介者
class GoodLight {
    Mediator* mediator;  // 只需要知道这一个
    
    void morningMode() {
        mediator->notify("light", "morning_mode");
    }
};

思维二:从“我控制别人”到“我只通知变化”

// ❌ 命令式思维:主动控制别人
class BadUserInterface {
    TextBox* nameBox;
    TextBox* emailBox;
    Button* submitBtn;
    
    void onNameChanged() {
        if(nameBox->getText().length() > 0) {
            emailBox->enable();
        }
        if(nameBox->getText().length() > 0 && 
           emailBox->getText().contains("@")) {
            submitBtn->enable();
        }
    }
};

// ✅ 声明式思维:只通知状态变化
class GoodUserInterface {
    Mediator* mediator;
    
    void onNameChanged() {
        mediator->notify("nameBox", "text_changed");
    }
};

思维三:从“硬编码路径”到“可配置策略”

可配置交互

统一接口

策略1

策略2

策略3

对象A

中介者配置中心

对象B

对象C

对象D

硬编码交互

直接调用

直接调用

对象A

对象B

对象C

思维四:从“点对点通信”到“事件驱动协作”

// 事件驱动的协作思维
class EventDrivenMediator : public Mediator {
    map<string, vector<function<void()>>> eventHandlers;
    
public:
    void registerHandler(string event, function<void()> handler) {
        eventHandlers[event].push_back(handler);
    }
    
    void notify(string sender, string event) override {
        // 事件驱动的协作:谁关心谁响应
        for(auto& handler : eventHandlers[event]) {
            handler();  // 多对多的协作,但彼此不知道
        }
    }
};

3. 深层哲学思想

3.1 解耦的极致:依赖倒置的应用

// 依赖倒置:都依赖抽象的中介者
class Colleague {
    Mediator* mediator;  // 依赖抽象,不依赖具体
};

// 具体交互策略可以自由变化
class FlexibleMediator : public Mediator {
    // 交互逻辑完全可配置,不影响同事类
    map<pair<string, string>, vector<string>> rules;
};

3.2 控制反转的体现

中介者同事对象中介者同事对象传统控制流:C控制M控制反转:M控制C执行这个、执行那个你需要做什么我完成了现在你需要做什么

3.3 关注点分离

// 交互逻辑与业务逻辑分离
class BusinessLogic {  // 只关心自己的业务
    void doWork() { /* 业务逻辑 */ }
};

class InteractionLogic {  // 中介者关心交互
    void coordinate() {
        // 协调多个 BusinessLogic 对象
    }
};

4. 高级思维模式

模式一:中介者作为协议

// 将交互协议封装在中介者中
class ProtocolMediator {
    // 就像网络协议一样,定义交互规则
    enum ProtocolState {
        HANDSHAKE,
        DATA_TRANSFER,
        TERMINATION
    };
    
    ProtocolState state;
    
    void handleMessage(Message msg) {
        switch(state) {
            case HANDSHAKE: /* 握手逻辑 */
            case DATA_TRANSFER: /* 数据传输 */
            case TERMINATION: /* 终止逻辑 */
        }
    }
};

模式二:中介者作为路由器

// 智能路由中介者
class RouterMediator {
    map<string, string> routingTable;  // 消息路由表
    
    void route(string from, string message) {
        string to = routingTable[message];
        // 根据消息内容智能路由到目标对象
    }
};

5. 思维的延伸应用

这个思维模式不仅适用于编程,也适用于:

  1. 组织管理:部门经理作为中介者协调员工
  2. 交通系统:交通灯作为中介者协调车辆
  3. 金融交易:交易所作为中介者匹配买卖订单

思维应用类比

编程思维
中介者模式

组织管理
部门经理协调

交通系统
交通灯控制

金融领域
交易所匹配

通信系统
交换机路由

6. 思维检查清单

使用中介者模式时,问自己:

  • 对象是否知道太多其他对象的细节?
  • 修改一个对象是否需要修改多个其他对象?
  • 对象的交互逻辑是否难以理解和维护?
  • 是否可以在不修改对象本身的情况下改变交互方式?
  • 是否可以将交互逻辑提取出来独立变化?

7. 思维陷阱提醒

⚠️ 不要把中介者变成“上帝对象”

// 坏味道:什么都知道的中介者
class GodMediator {
    Light* light;
    AC* ac;
    TV* tv;
    Speaker* speaker;
    Curtain* curtain;
    // ... 100+ 个成员变量
    
    void doEverything() {
        // 包含所有业务逻辑
    }
};

正确思维:应该拆分为多个专门的中介者

// 好味道:职责单一的中介者
class LightingMediator { /* 只管理灯光 */ };
class ClimateMediator { /* 只管理温控 */ };
class EntertainmentMediator { /* 只管理娱乐 */ };

第三部分:总结与最佳实践

核心总结

中介者模式的本质思维:

  • 减少认知负担:每个对象只需要认识中介者
  • 改变控制流向:从对象间相互控制到中介者集中控制
  • 提取变化点:将易变的交互逻辑封装在中介者中
  • 面向接口协作:所有交互都通过抽象中介者接口

核心价值: 通过增加一个间接层,将网状复杂度转换为星型简洁度,从而让系统更容易理解、维护和扩展。

最佳实践建议

  1. 适用判断:当系统中存在多对多的复杂交互关系时考虑使用
  2. 避免上帝对象:将复杂的中介者拆分为多个专门的中介者
  3. 结合工厂模式:使用工厂创建同事对象,降低耦合
  4. 异步处理:对于耗时操作,考虑使用异步消息队列
  5. 命名规范:中介者命名应体现其协调职责(如 XxxCoordinatorXxxHub

这个模式在实际开发中非常实用,特别是处理复杂UI组件交互、工作流引擎、智能家居控制等场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值