行为型模式:⑤中介者模式(Mediator Pattern)

行为型模式:⑤中介者模式(Mediator Pattern)

核心思想

定义一个中介者对象,封装多个对象(同事类)之间的交互逻辑,使同事类之间无需直接通信,仅通过中介者传递消息,从而降低同事类的耦合度,集中管理交互规则,便于维护和扩展。

核心本质

交互集中化,将 “网状交织的同事交互” 转化为 “星状的中介者 - 同事交互”,解决多对象依赖导致的耦合爆炸问题。

典型场景

团队协作系统(如项目组内成员通过项目经理传递信息);
聊天软件(用户通过服务器转发消息,无需直接连接);
界面组件交互(如按钮点击后,通过中介者更新输入框、列表框等多个组件);
分布式系统中的协调器(如微服务注册中心、配置中心)。

C 语言实现(结构体 + 函数指针 + 集中交互)

C 语言无类,通过 “结构体模拟角色”“函数指针定义接口”“中介者持有同事列表”,实现同事间的间接通信。核心是:中介者维护所有同事的引用,同事发送消息时委托中介者转发,中介者负责调用目标同事的接收逻辑。

场景示例

办公室消息通知系统:
抽象中介者(Mediator):定义 “注册同事”“转发消息” 接口;
具体中介者(AdminMediator):行政部,维护员工列表,转发消息给所有 / 指定员工;
同事类(Colleague):员工,持有中介者指针,支持 “发送消息”“接收消息”;
具体同事类(Employee):实际员工,通过行政部发送消息,接收行政部转发的消息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 最大同事数量
#define MAX_COLLEAGUES 10
// 最大消息长度
#define MAX_MSG_LEN 128
// 最大用户名长度
#define MAX_NAME_LEN 32

// 前置声明:同事结构体(供中介者使用)
typedef struct Colleague Colleague;

// -------------------------- 1. 抽象中介者(Mediator):统一交互接口 --------------------------
typedef struct Mediator {
    // 注册同事(将同事加入中介者管理列表)
    void (*register_colleague)(struct Mediator* self, Colleague* colleague);
    // 转发消息(同事发送的消息通过中介者转发)
    void (*forward_message)(struct Mediator* self, const Colleague* sender, const char* msg);
    // 销毁中介者
    void (*destroy)(struct Mediator* self);
    // 管理的同事列表
    Colleague* colleagues[MAX_COLLEAGUES];
    int colleague_count; // 已注册同事数量
} Mediator;

// -------------------------- 2. 同事类(Colleague):与中介者交互的对象 --------------------------
struct Colleague {
    char name[MAX_NAME_LEN];       // 同事名称(如员工姓名)
    Mediator* mediator;            // 持有中介者指针(关键:通过中介者通信)
    // 发送消息(委托中介者转发)
    void (*send_msg)(struct Colleague* self, const char* msg);
    // 接收消息(中介者调用此方法传递消息)
    void (*recv_msg)(struct Colleague* self, const char* sender, const char* msg);
    // 销毁同事
    void (*destroy)(struct Colleague* self);
};

// -------------------------- 3. 具体中介者(AdminMediator):行政部(实现转发逻辑) --------------------------
typedef struct AdminMediator {
    Mediator base; // 继承抽象中介者接口
} AdminMediator;

// 具体中介者:注册同事
void admin_register_colleague(Mediator* self, Colleague* colleague) {
    if (self->colleague_count >= MAX_COLLEAGUES) {
        printf("[行政部] 同事数量已达上限,无法注册新同事!\n");
        return;
    }
    self->colleagues[self->colleague_count++] = colleague;
    printf("[行政部] 员工「%s」已注册到消息系统\n", colleague->name);
}

// 具体中介者:转发消息(发给所有其他同事)
void admin_forward_message(Mediator* self, const Colleague* sender, const char* msg) {
    printf("\n[行政部] 收到「%s」的消息:%s → 开始转发给所有员工...\n", sender->name, msg);
    // 遍历所有同事,排除发送者,调用接收消息方法
    for (int i = 0; i < self->colleague_count; i++) {
        Colleague* receiver = self->colleagues[i];
        if (receiver != sender) { // 不转发给发送者自己
            receiver->recv_msg(receiver, sender->name, msg);
        }
    }
}

// 具体中介者:销毁(无需额外释放,同事由客户端单独销毁)
void admin_destroy(Mediator* self) {
    free(self);
    printf("\n[行政部] 消息系统已关闭\n");
}

// 创建具体中介者(行政部)
Mediator* create_admin_mediator() {
    AdminMediator* admin = (AdminMediator*)malloc(sizeof(AdminMediator));
    admin->base.register_colleague = admin_register_colleague;
    admin->base.forward_message = admin_forward_message;
    admin->base.destroy = admin_destroy;
    admin->base.colleague_count = 0;
    memset(admin->base.colleagues, 0, sizeof(admin->base.colleagues));
    return (Mediator*)admin;
}

// -------------------------- 4. 具体同事类(Employee):员工(实现发送/接收逻辑) --------------------------
typedef struct Employee {
    Colleague base; // 继承同事接口
} Employee;

// 具体同事:发送消息(委托中介者转发)
void employee_send_msg(Colleague* self, const char* msg) {
    if (self->mediator == NULL) {
        printf("[%s] 未注册到消息系统,无法发送消息!\n", self->name);
        return;
    }
    printf("[%s] 发送消息:%s\n", self->name, msg);
    self->mediator->forward_message(self->mediator, self, msg);
}

// 具体同事:接收消息
void employee_recv_msg(Colleague* self, const char* sender, const char* msg) {
    printf("[%s] 收到「%s」的消息:%s\n", self->name, sender, msg);
}

// 具体同事:销毁
void employee_destroy(Colleague* self) {
    free(self);
    printf("[%s] 已退出消息系统\n", self->name);
}

// 创建具体同事(员工)
Colleague* create_employee(const char* name, Mediator* mediator) {
    Employee* emp = (Employee*)malloc(sizeof(Employee));
    strncpy(emp->base.name, name, MAX_NAME_LEN);
    emp->base.mediator = mediator; // 绑定中介者
    emp->base.send_msg = employee_send_msg;
    emp->base.recv_msg = employee_recv_msg;
    emp->base.destroy = employee_destroy;
    return (Colleague*)emp;
}

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建中介者(行政部)
    Mediator* admin = create_admin_mediator();

    // 2. 创建同事(员工)并注册到中介者
    Colleague* zhangsan = create_employee("张三", admin);
    Colleague* lisi = create_employee("李四", admin);
    Colleague* wangwu = create_employee("王五", admin);

    admin->register_colleague(admin, zhangsan);
    admin->register_colleague(admin, lisi);
    admin->register_colleague(admin, wangwu);

    // 3. 同事发送消息(通过中介者转发)
    zhangsan->send_msg(zhangsan, "明天上午10点开项目例会,请大家准时参加!");
    lisi->send_msg(lisi, "会议资料已上传到共享盘,链接:xxx");
    wangwu->send_msg(wangwu, "收到,准时参会~");

    // 4. 销毁资源
    printf("\n=== 退出消息系统 ===");
    zhangsan->destroy(zhangsan);
    lisi->destroy(lisi);
    wangwu->destroy(wangwu);
    admin->destroy(admin);

    return 0;
}

实现关键要点

1.中介者持有同事列表:具体中介者(AdminMediator)通过数组维护所有注册的同事,确保能遍历转发消息,是 “集中交互” 的核心。
2.同事依赖中介者:每个同事(Employee)持有中介者指针,发送消息时不直接调用其他同事,而是委托中介者的 forward_message 方法,彻底解耦同事间的直接依赖。
3.接口统一:抽象中介者(Mediator)和同事(Colleague)通过函数指针定义统一接口,具体实现类(AdminMediator/Employee)绑定对应逻辑,客户端无需区分具体类型。
4.交互逻辑集中:所有同事间的通信规则(如 “转发给所有其他同事”)都集中在中介者中,修改交互规则时仅需修改中介者,无需修改同事代码,符合 “单一职责原则”。
5.扩展性:新增同事(如 “赵六”)时,仅需创建 Employee 并注册到中介者;新增交互规则(如 “转发给指定部门员工”)时,仅需修改中介者的 forward_message 方法,符合 “开闭原则”。
6.内存管理:同事和中介者需手动销毁,中介者不负责同事的生命周期(客户端单独管理),避免循环引用导致的内存泄漏。

C++ 实现(类 + 继承 + 多态 + 集中管理)

通过 “抽象基类 + 继承” 定义中介者和同事接口,利用多态实现灵活交互,STL 容器简化同事管理,智能指针自动维护内存,代码更简洁、类型更安全。

场景示例

同 C 语言:办公室消息通知系统,抽象中介者 Mediator、具体中介者 AdminMediator、抽象同事 Colleague、具体同事 Employee,同事通过中介者转发消息。

#include <iostream>
#include <string>
#include <vector>
#include <memory> // 智能指针(自动管理内存)

using namespace std;

// 前置声明:同事类(供中介者使用)
class Colleague;

// -------------------------- 1. 抽象中介者(Mediator):抽象基类 --------------------------
class Mediator {
public:
    virtual ~Mediator() = default; // 虚析构:确保子类析构被调用
    // 纯虚函数:注册同事
    virtual void registerColleague(shared_ptr<Colleague> colleague) = 0;
    // 纯虚函数:转发消息
    virtual void forwardMessage(const Colleague* sender, const string& msg) = 0;
};

// -------------------------- 2. 抽象同事(Colleague):抽象基类 --------------------------
class Colleague {
public:
    Colleague(string name, shared_ptr<Mediator> mediator)
        : name_(move(name)), mediator_(move(mediator)) {}

    virtual ~Colleague() = default;

    // 纯虚函数:发送消息
    virtual void sendMsg(const string& msg) = 0;
    // 纯虚函数:接收消息
    virtual void recvMsg(const string& sender, const string& msg) = 0;

    // 获取同事名称(供中介者使用)
    string getName() const { return name_; }

protected:
    string name_;                  // 同事名称
    shared_ptr<Mediator> mediator_;// 持有中介者智能指针(解耦+自动内存管理)
};

// -------------------------- 3. 具体中介者(AdminMediator):行政部 --------------------------
class AdminMediator : public Mediator {
public:
    void registerColleague(shared_ptr<Colleague> colleague) override {
        // 用vector存储同事智能指针,自动管理同事生命周期
        colleagues_.push_back(colleague);
        cout << "[行政部] 员工「" << colleague->getName() << "」已注册到消息系统" << endl;
    }

    void forwardMessage(const Colleague* sender, const string& msg) override {
        cout << "\n[行政部] 收到「" << sender->getName() << "」的消息:" << msg 
             << " → 开始转发给所有员工..." << endl;
        // 遍历所有同事,转发消息(排除发送者)
        for (const auto& colleague : colleagues_) {
            if (colleague.get() != sender) { // 避免给自己发消息
                colleague->recvMsg(sender->getName(), msg);
            }
        }
    }

private:
    // 存储同事智能指针,避免野指针,自动释放
    vector<shared_ptr<Colleague>> colleagues_;
};

// -------------------------- 4. 具体同事(Employee):员工 --------------------------
class Employee : public Colleague {
public:
    Employee(string name, shared_ptr<Mediator> mediator)
        : Colleague(move(name), move(mediator)) {}

    void sendMsg(const string& msg) override {
        if (!mediator_) {
            cout << "[" << name_ << "] 未注册到消息系统,无法发送消息!" << endl;
            return;
        }
        cout << "[" << name_ << "] 发送消息:" << msg << endl;
        // 委托中介者转发消息
        mediator_->forwardMessage(this, msg);
    }

    void recvMsg(const string& sender, const string& msg) override {
        cout << "[" << name_ << "] 收到「" << sender << "」的消息:" << msg << endl;
    }
};

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建中介者(智能指针自动管理内存)
    auto admin = make_shared<AdminMediator>();

    // 2. 创建同事(员工)并注册到中介者
    auto zhangsan = make_shared<Employee>("张三", admin);
    auto lisi = make_shared<Employee>("李四", admin);
    auto wangwu = make_shared<Employee>("王五", admin);

    admin->registerColleague(zhangsan);
    admin->registerColleague(lisi);
    admin->registerColleague(wangwu);

    // 3. 同事发送消息
    zhangsan->sendMsg("明天上午10点开项目例会,请大家准时参加!");
    lisi->sendMsg("会议资料已上传到共享盘,链接:xxx");
    wangwu->sendMsg("收到,准时参会~");

    return 0; // 智能指针自动销毁所有对象,无需手动释放
}

实现关键要点

1.抽象基类定义接口:Mediator 和 Colleague 为抽象基类,纯虚函数定义统一交互接口(registerColleague/forwardMessage、sendMsg/recvMsg),具体类继承并实现,确保多态调用。
2.智能指针管理内存:中介者和同事均用 shared_ptr 管理,自动处理生命周期,避免野指针和内存泄漏;虚析构函数确保子类析构被正确调用。
3.解耦彻底:同事仅依赖 Mediator 抽象基类,不依赖具体中介者或其他同事;中介者仅依赖 Colleague 抽象基类,不依赖具体同事,符合 “依赖倒置原则”。
4.STL 容器简化管理:中介者用 vector 存储同事智能指针,无需手动维护数组索引和容量,遍历转发更简洁。
5.交互逻辑集中:所有同事间的通信规则集中在 AdminMediator 的 forwardMessage 方法中,修改规则(如按部门转发、私信功能)仅需修改中介者,无需改动同事代码。
6.扩展性强:新增同事(如 “赵六”)仅需创建 Employee 实例并注册;新增中介者(如 “技术部中介者”)仅需继承 Mediator 并实现接口,客户端代码无需修改,符合 “开闭原则”。
7.类型安全:C++ 的编译期类型检查和多态机制,避免 C 语言中函数指针绑定错误或类型转换风险,代码更可靠。

中介者模式核心总结(C vs C++)

在这里插入图片描述

设计原则

单一职责原则:中介者管交互,同事管自身业务,各司其职;
开闭原则:新增同事或交互规则,无需修改现有代码;
依赖倒置原则:同事和中介者均依赖抽象,不依赖具体实现;
迪米特法则(最少知识原则):同事仅与中介者通信,不与其他同事直接交互,减少依赖。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值