设计模式:中介者模式 Mediator

目录


前言

中介者是一种行为设计模式,能让你减少对象之间混乱无序的依赖关系。该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。


问题

假如你有一个创建和修改客户资料的对话框, 它由各种控件组成, 例如 文本框(TextField)、复选框(Checkbox) 和 按钮(Button)等。

某些表单元素可能会直接进行互动。 例如, 选中"我有一只狗"复选框后可能会显示一个隐藏文本框用于输入狗狗的名字。 另一个例子是提交按钮必须在保存数据前校验所有输入内容。

如果直接在表单元素代码中实现业务逻辑, 你将很难在程序其他表单中复用这些元素类。 例如, 由于复选框类与狗狗的文本框相耦合, 所以将无法在其他表单中使用它。 你要么使用渲染资料表单时用到的所有类,要么一个都不用。

解决方案

中介者模式建议你停止组件之间的直接交流并使其相互独立。这些组件必须调用特殊的中介者对象, 通过中介者对象重定向调用行为,以间接的方式进行合作。最终,组件仅依赖于一个中介者类,无需与多个其他组件相耦合。

在资料编辑表单的例子中, 对话框(Dialog) 类本身将作为中介者, 其很可能已知自己所有的子元素, 因此你甚至无需在该类中引入新的依赖关系。

绝大部分重要的修改都在实际表单元素中进行。 让我们想想提交按钮。之前,当用户点击按钮后,它必须对所有表单元素数值进行校验。 而现在它的唯一工作是将点击事件通知给对话框。 收到通知后, 对话框可以自行校验数值或将任务委派给各元素。 这样一来, 按钮不再与多个表单元素相关联,而仅依赖于对话框类。

你还可以为所有类型的对话框抽取通用接口, 进一步削弱其依赖性。 接口中将声明一个所有表单元素都能使用的通知方法, 可用于将元素中发生的事件通知给对话框。 这样一来,所有实现了该接口的对话框都能使用这个提交按钮了。

采用这种方式, 中介者模式让你能在单个中介者对象中封装多个对象间的复杂关系网。 类所拥有的依赖关系越少, 就越易于修改、扩展或复用。

结构

代码

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>
#include <map>
using namespace std;

class AbstractComponent{
public:
    virtual void operation()=0;
    virtual ~AbstractComponent(){}
};

class AbstractMediator{
public:
    virtual void notify(const string& sender)=0;
    virtual void addComponent(const string& name,shared_ptr<AbstractComponent> component)=0;
    virtual ~AbstractMediator(){}
};
class Dialog:public AbstractMediator{
public:
    void notify(const string& sender) override {
        if (sender == "button") {
            // 当按钮被触发时,协调复选框也执行操作
            cout << "中介者:按钮被按下,触发复选框操作" << endl;
            if (m_component.find("checkbox") != m_component.end()) {
                m_component["checkbox"]->operation();
            }
        } else if (sender == "checkbox") {
            cout<<"end"<<endl;
        }
    }
    void addComponent(const string& name,shared_ptr<AbstractComponent> component){
        m_component.insert(make_pair(name,component));
    }
private:
    map<string,shared_ptr<AbstractComponent>> m_component;
};

class Button:public AbstractComponent{
public:
    Button(shared_ptr<AbstractMediator> mediator){m=mediator;}
    void operation() override {
        cout << "按钮被按下" << endl;
        // 自身状态变化后,通过中介者通知其他组件
        m->notify("button"); 
    }
private:
    shared_ptr<AbstractMediator> m;
};
class Checkbox:public AbstractComponent{
public:
    Checkbox(shared_ptr<AbstractMediator> mediator){m=mediator;}
    void operation() override{
        cout << "调用复选框" << endl;
        // 自身状态变化后,通过中介者通知其他组件
        m->notify("checkbox"); 
    }
private:
    shared_ptr<AbstractMediator> m;
};

int main(){
    auto dialog=make_shared<Dialog>();
    auto button=make_shared<Button>(dialog);
    auto checkbox=make_shared<Checkbox>(dialog);

    dialog->addComponent("button",button);
    dialog->addComponent("checkbox",checkbox);
    
    button->operation();
    cout<<"----------------"<<endl;
    checkbox->operation();

    return 0;
}
相关推荐
写bug写bug8 小时前
你真的会用枚举吗
java·后端·设计模式
哆啦code梦9 小时前
趣谈设计模式之策略模式-比特咖啡给你一杯满满的情绪价值,让您在数字世界里”畅饮“
设计模式·策略模式
华仔啊13 小时前
别学23种了!Java项目中最常用的6个设计模式,附案例
java·后端·设计模式
Keya16 小时前
MacOS端口被占用的解决方法
前端·后端·设计模式
已读不回14317 小时前
设计模式-单例模式
前端·设计模式
long3162 天前
构建者设计模式 Builder
java·后端·学习·设计模式
一乐小哥2 天前
从 JDK 到 Spring,单例模式在源码中的实战用法
后端·设计模式
付春员2 天前
23种设计模式
设计模式
Zyy~2 天前
《设计模式》工厂方法模式
设计模式·工厂方法模式
ikkkkkkkl2 天前
C++设计模式:面向对象设计原则
c++·设计模式·面向对象