c/c++设计模式-----中介者模式

中介者模式概念:

在软件设计中,中介者模式(Mediator Pattern)是一种行为设计模式,它可以用来减少对象之间的直接依赖性,通过引入一个中介者对象来协调各个对象的交互。这样做的好处是,可以将对象间复杂的网状关系简化为星状关系,有助于提高系统的可维护性和扩展性。

没有中间者(主板)

 

有中介者(主板):

一个游戏登录框:

 

 

namespace _nmsp1
{
    //UI控件类的父类
    class CtlParent
    {
    public:
        CtlParent(string caption) :m_caption(caption) {} //构造函数
        virtual ~CtlParent() {} //做父类时析构函数应该为虚函数

    public:
        //当UI控件发生变化时该成员函数会被调用
        virtual void Changed(map<string, CtlParent*>& tmpuictllist) = 0; //形参所代表的map容器中包含着所有对话框中涉及的UI控件。
        //设置UI控件启用或者禁用
        virtual void Enable(bool sign) = 0;

    protected:
        string m_caption; //控件上面显示的文字内容,本范例假设每个UI空间上的文字都不同
    };

    //普通按钮相关类
    class Button :public CtlParent
    {
    public:
        Button(string caption) :CtlParent(caption) {} //构造函数
        //设置按钮的启用或者禁用
        virtual void Enable(bool sign)
        {
            if (sign == true)
            {
                cout << "按钮\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
            }
            else
            {
                cout << "按钮\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
            }
            //......具体实现按钮启用或者禁用的代码。。。。
        }
        //按钮被按下时该成员函数会被调用
        virtual void Changed(map<string, CtlParent*>& tmpuictllist);
    };
    
    //单选按钮相关类
    class RadioBtn :public CtlParent
    {
    public:
        RadioBtn(string caption) :CtlParent(caption) {} //构造函数
        //设置单选按钮的启用或者禁用
        virtual void Enable(bool sign)
        {
            //本范例用不到该功能,实现代码略......
        }
        //设置单选按钮被选中或者被取消选中,被选中的单选按钮中间有个黑色的实心圆点
        void Selected(bool sign)
        {
            if (sign == true)
            {
                cout << "单选按钮\"" << m_caption << "\"被选中" << endl;
            }
            else
            {
                cout << "单选按钮\"" << m_caption << "\"被取消选中" << endl;
            }
            //......具体实现单选按钮启用或者取消选中的代码略。。。。。
        }
        
        //单选按钮被单击时该成员函数会被调用
        virtual void Changed(map<string, CtlParent*>& tmpuictllist);
    };

    //编辑框相关类
    class EditCtl :public CtlParent
    {
    public:
        EditCtl(string caption) :CtlParent(caption) {} //构造函数
        //设置编辑框的启用或者禁用
        virtual void Enable(bool sign)
        {
            if (sign == true)
            {
                cout << "编辑框\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
            }
            else
            {
                cout << "编辑框\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
            }
            //......具体实现编辑框启用或者禁用的代码。。。。
        }

        //是否编辑框中的内容为空
        bool isContentEmpty()
        {
            return m_content.empty();
        }

        //编辑框内容发生变化时该成员函数会被调用
        virtual void Changed(map<string, CtlParent*>& tmpuictllist);

    private:
        string m_content = ""; //编辑框中的内容
    };

    //---------------------------
    //普通按钮被按下是该成员函数会被调用
    void Button::Changed(map<string, CtlParent*>& tmpuictllist)
    {
        if (m_caption == "登录")
        {
            //按下的是登录按钮
            cout << "开始游戏登录验证,根据验证结果决定是否进入游戏之中还是验证失败给出提示!" << endl;
        }
        else if (m_caption == "退出")
        {
            //按下的是退出按钮,则退出整个游戏
            cout << "游戏退出,再见!" << endl;
        }
    }

    //单选按钮被单击时该成员函数会被调用
    void RadioBtn::Changed(map<string, CtlParent*>& tmpuictllist)
    {
        if (m_caption == "游客登录")
        {
            (static_cast<RadioBtn*>(tmpuictllist["游客登录"]))->Selected(true); //游客登录 单选按钮被选中
            (static_cast<RadioBtn*>(tmpuictllist["账号登录"]))->Selected(false); //账号登录 单选按钮被取消选中

            tmpuictllist["账号"]->Enable(false); //账号 编辑框设置为禁用
            tmpuictllist["密码"]->Enable(false); //密码 编辑框设置为禁用

            tmpuictllist["登录"]->Enable(true);  //登录 按钮设置为启用
        }
        else if (m_caption == "账号登录")
        {
            (static_cast<RadioBtn*>(tmpuictllist["账号登录"]))->Selected(true); //账号登录 单选按钮被选中
            (static_cast<RadioBtn*>(tmpuictllist["游客登录"]))->Selected(false); //游客登录 单选按钮被取消选中

            tmpuictllist["账号"]->Enable(true); //账号 编辑框设置为启用
            tmpuictllist["密码"]->Enable(true); //密码 编辑框设置为启用

            if ((static_cast<EditCtl*>(tmpuictllist["账号"]))->isContentEmpty()
                || (static_cast<EditCtl*>(tmpuictllist["密码"]))->isContentEmpty())
            {
                //如果 账号 编辑框 或者 密码 编辑框 有一个为空,则不允许登录
                tmpuictllist["登录"]->Enable(false); //登录 按钮设置为禁用
            }
            else
            {
                tmpuictllist["登录"]->Enable(true); //登录 按钮设置为启用
            }            
        }
    }

    //编辑框内容发生变化时该成员函数会被调用
    void EditCtl::Changed(map<string, CtlParent*>& tmpuictllist)
    {
        if ((static_cast<EditCtl*>(tmpuictllist["账号"]))->isContentEmpty()
            || (static_cast<EditCtl*>(tmpuictllist["密码"]))->isContentEmpty())
        {
            //如果 账号 编辑框 或者 密码 编辑框 有一个为空,则不允许登录
            tmpuictllist["登录"]->Enable(false); //登录 按钮设置为禁用
        }
        else
        {
            tmpuictllist["登录"]->Enable(true); //登录 按钮设置为启用
        }
    }
}

int main()
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口


    //创建各种UI控件
    map<string, _nmsp1::CtlParent*> uictllist; //将所有创建的UI控件保存到map容器中,方便进行参数传递
    uictllist["登录"] = new _nmsp1::Button("登录");
    uictllist["退出"] = new _nmsp1::Button("退出");

    uictllist["游客登录"] = new _nmsp1::RadioBtn("游客登录");
    uictllist["账号登录"] = new _nmsp1::RadioBtn("账号登录");

    uictllist["账号"] = new _nmsp1::EditCtl("账号");
    uictllist["密码"] = new _nmsp1::EditCtl("密码");

    //设置一下缺省的UI控件状态
    (static_cast<_nmsp1::RadioBtn*>(uictllist["游客登录"]))->Selected(true); //游客登录 单选按钮被选中
    (static_cast<_nmsp1::RadioBtn*>(uictllist["账号登录"]))->Selected(false); //账号登录 单选按钮被取消选中

    uictllist["账号"]->Enable(false); //账号  编辑框设置为禁用
    uictllist["密码"]->Enable(false); //密码  编辑框设置为禁用

    uictllist["登录"]->Enable(true); //登录  按钮设置为启用
    uictllist["退出"]->Enable(true); //退出  按钮设置为启用

    cout << "------------------------" << endl;
    uictllist["账号登录"]->Changed(uictllist); //模拟 账号登录 单选按钮被单击选中



    //释放资源
    for (auto iter = uictllist.begin(); iter != uictllist.end(); ++iter)
    {
        delete iter->second;
        iter->second = nullptr;
    }


    return 0;
}

中介者(Mediator)模式:调停者模式,行为型模式。
//a)计算的各个组成部件:主板
//b)qq聊天:与好友或者陌生人单独聊天(私聊);加入到一个qq群中。
//c)飞机的安全飞行与安全着陆:塔台

 

 

 

//(2)中介者模式范例的引入:事件类驱动的软件中有比较广泛的应用,尤其是常常运用在程序的UI界面设计中

 

namespace _nmsp2
{
    //类的前向声明
    class CtlParent;

    //中介者父类
    class Mediator
    {
    public:
        virtual ~Mediator() {} //做父类时析构函数应该为虚函数
    public:
        virtual void createCtrl() = 0; //创建所有需要用到的UI控件
        virtual void ctlChanged(CtlParent*) = 0; //当某个UI控件发生变化时调用中介者对象的该成员函数来通知中介者
    };

    //UI控件类的父类
    class CtlParent
    {
    public:
        CtlParent(Mediator* ptmpm, string caption) :m_pmediator(ptmpm), m_caption(caption) {} //构造函数
        virtual ~CtlParent() {} //做父类时析构函数应该为虚函数

    public:
        //当UI控件发生变化时该成员函数会被调用
        virtual void Changed()
        {
            m_pmediator->ctlChanged(this); //通知中介者对象,所有事情让中介者对象去做
        }

        //设置UI控件的启用或禁用
        virtual void Enable(bool sign) = 0;

    protected:
        Mediator* m_pmediator; //指向中介者对象的指针
        string m_caption; //控件上面显示的文字内容,可能并不是所有控件都需要但这里为显示方便依旧引入
    };

    //普通按钮相关类
    class Button :public CtlParent
    {
    public:
        Button(Mediator* ptmpm, string caption) :CtlParent(ptmpm, caption) {} //构造函数
        //设置按钮的启用或者禁用
        virtual void Enable(bool sign)
        {
            if (sign == true)
            {
                cout << "按钮\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
            }
            else
            {
                cout << "按钮\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
            }
            //具体实现按钮启用或者禁用的代码略......
        }
    };

    //单选按钮相关类
    class RadioBtn :public CtlParent
    {
    public:
        RadioBtn(Mediator* ptmpm, string caption) :CtlParent(ptmpm, caption) {} //构造函数
        //设置按钮的启用或者禁用
        virtual void Enable(bool sign)
        {
            //用不到该功能,实现代码略......
        }
        //设置单选按钮为被选中或者被取消选中,被选中的单选按钮中间有个黑色实心圆点
        void Selected(bool sign)
        {
            if (sign == true)
            {
                cout << "单选按钮\"" << m_caption << "\"被选中" << endl;
            }
            else
            {
                cout << "单选按钮\"" << m_caption << "\"被取消选中" << endl;
            }
            //具体实现单选按钮被选中或者被取消选中的代码略......
        }
    };

    //编辑框相关类
    class EditCtl :public CtlParent
    {
    public:
        EditCtl(Mediator* ptmpm, string caption) :CtlParent(ptmpm, caption) {} //构造函数
        //设置编辑框的启用或者禁用
        virtual void Enable(bool sign)
        {
            if (sign == true)
            {
                cout << "编辑框\"" << m_caption << "\"被设置为了\"启用\"状态" << endl;
            }
            else
            {
                cout << "编辑框\"" << m_caption << "\"被设置为了\"禁用\"状态" << endl;
            }
            //具体实现编辑框启用或者禁用的代码略......
        }
        //是否编辑框中的内容为空
        bool isContentEmpty()
        {
            return m_content.empty();
        }
        //其他成员函数略......
    private:
        string m_content = ""; //编辑框中的内容
    };

    //----------------
    //具体中介者类
    class concreMediator : public Mediator
    {

    public:
        ~concreMediator() //析构函数
        {
            if (mp_login) {delete mp_login; mp_login = nullptr;}
            if (mp_logout) { delete mp_logout; mp_logout = nullptr; }

            if (mp_rbtn1) { delete mp_rbtn1; mp_rbtn1 = nullptr; }
            if (mp_rbtn2) { delete mp_rbtn2; mp_rbtn2 = nullptr; }

            if (mp_edtctl1) { delete mp_edtctl1; mp_edtctl1 = nullptr; }
            if (mp_edtctl2) { delete mp_edtctl2; mp_edtctl2 = nullptr; }
        }
        virtual void createCtrl()
        {
            //当然,各种UI控件对象在外面创建,然后把地址传递进来也可以
            mp_login = new Button(this, "登录");
            mp_logout = new Button(this, "退出");

            mp_rbtn1 = new RadioBtn(this, "游客登录");
            mp_rbtn2 = new RadioBtn(this, "账号登录");

            mp_edtctl1 = new EditCtl(this, "账号编辑框");
            mp_edtctl2 = new EditCtl(this, "密码编辑框");

            //设置一下缺省的UI控件状态
            mp_rbtn1->Selected(true); //"游客登录"单选按钮设置为选中
            mp_rbtn2->Selected(false); //"账号登录"单选按钮设置为取消选中

            mp_edtctl1->Enable(false); //"账号"编辑框设置为禁用
            mp_edtctl2->Enable(false); //"密码"编辑框设置为禁用

            mp_login->Enable(true); //"登录"按钮设置为启用
            mp_logout->Enable(true); //"退出"按钮设置为启用

            //UI控件的位置设置等代码略......
        }

        virtual void ctlChanged(CtlParent* p_ctrl)
        {
            if (p_ctrl == mp_login) //登录按钮被单击
            {
                cout << "开始游戏登录验证,根据验证结果决定是进入游戏之中还是验证失败给出提示!" << endl;
            }
            else if (p_ctrl == mp_logout) //退出按钮被单击
            {
                cout << "游戏退出,再见!" << endl;
            }

            if (p_ctrl == mp_rbtn1) //游客登录单选按钮被单击
            {
                mp_rbtn1->Selected(true); //"游客登录"单选按钮设置为选中 
                mp_rbtn2->Selected(false); //"账号登录"单选按钮设置为取消选中 

                mp_edtctl1->Enable(false); //"账号"编辑框设置为禁用
                mp_edtctl2->Enable(false); //"密码"编辑框设置为禁用

                mp_login->Enable(true); //"登录"按钮设置为启用
            }
            else if (p_ctrl == mp_rbtn2) //账号登录单选按钮被单击
            {
                mp_rbtn1->Selected(false); //"游客登录"单选按钮设置为取消选中 
                mp_rbtn2->Selected(true); //"账号登录"单选按钮设置为选中 

                mp_edtctl1->Enable(true); //"账号"编辑框设置为启用
                mp_edtctl2->Enable(true); //"密码"编辑框设置为启用

                if (mp_edtctl1->isContentEmpty() || mp_edtctl2->isContentEmpty())
                {
                    //如果"账号"编辑框或者"密码"编辑框有一个为空,则不允许登录
                    mp_login->Enable(false); //"登录"按钮设置为禁用
                }
                else
                {
                    mp_login->Enable(true); //"登录"按钮设置为启用
                }
            }

            if (p_ctrl == mp_edtctl1 || p_ctrl == mp_edtctl2) //账号或者密码编辑框内容发生改变
            {
                if (mp_edtctl1->isContentEmpty() || mp_edtctl2->isContentEmpty())
                {
                    //如果"账号"编辑框或者"密码"编辑框有一个为空,则不允许登录
                    mp_login->Enable(false); //"登录"按钮设置为禁用
                }
                else
                {
                    mp_login->Enable(true); //"登录"按钮设置为启用
                }
            }
        }

    public: //为了方便外界使用,这里以public修饰,实际项目中可以写一个成员函数来return这些指针
        Button* mp_login = nullptr; //登录按钮
        Button* mp_logout = nullptr; //退出按钮

        RadioBtn* mp_rbtn1 = nullptr; //游客登录单选按钮
        RadioBtn* mp_rbtn2 = nullptr; //账号登录单选按钮

        EditCtl* mp_edtctl1 = nullptr; //账号编辑框
        EditCtl* mp_edtctl2 = nullptr; //密码编辑框
    };
}

int main()
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);//程序退出时检测内存泄漏并显示到“输出”窗口


    /*
    //创建各种UI控件
    map<string, _nmsp1::CtlParent*> uictllist; //将所有创建的UI控件保存到map容器中,方便进行参数传递
    uictllist["登录"] = new _nmsp1::Button("登录");
    uictllist["退出"] = new _nmsp1::Button("退出");

    uictllist["游客登录"] = new _nmsp1::RadioBtn("游客登录");
    uictllist["账号登录"] = new _nmsp1::RadioBtn("账号登录");

    uictllist["账号"] = new _nmsp1::EditCtl("账号");
    uictllist["密码"] = new _nmsp1::EditCtl("密码");

    //设置一下缺省的UI控件状态
    (static_cast<_nmsp1::RadioBtn*>(uictllist["游客登录"]))->Selected(true); //游客登录 单选按钮被选中
    (static_cast<_nmsp1::RadioBtn*>(uictllist["账号登录"]))->Selected(false); //账号登录 单选按钮被取消选中

    uictllist["账号"]->Enable(false); //账号  编辑框设置为禁用
    uictllist["密码"]->Enable(false); //密码  编辑框设置为禁用

    uictllist["登录"]->Enable(true); //登录  按钮设置为启用
    uictllist["退出"]->Enable(true); //退出  按钮设置为启用

    cout << "------------------------" << endl;
    uictllist["账号登录"]->Changed(uictllist); //模拟 账号登录 单选按钮被单击选中



    //释放资源
    for (auto iter = uictllist.begin(); iter != uictllist.end(); ++iter)
    {
        delete iter->second;
        iter->second = nullptr;
    }
    */

    _nmsp2::concreMediator mymedia;
    mymedia.createCtrl();
    cout << "-------当\"账号登录\"单选按钮被按下时:---------" << endl;
    mymedia.mp_rbtn2->Changed(); //模拟"账号登录"单选按钮被按下,则去通知中介者,由中介者实现具体的逻辑处理

    return 0;
}

 

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

// 前向声明
class Colleague;
class ConcreteColleagueA;
class ConcreteColleagueB;

// 抽象中介者类
class Mediator {
public:
    virtual void sendMessage(const std::string &message, Colleague *colleague) = 0;
};

// 抽象同事类
class Colleague {
protected:
    Mediator *mediator;

public:
    Colleague(Mediator *mediator) : mediator(mediator) {}
    virtual void receiveMessage(const std::string &message) = 0;
};

// 具体同事类A
class ConcreteColleagueA : public Colleague {
public:
    ConcreteColleagueA(Mediator *mediator) : Colleague(mediator) {}

    void sendMessage(const std::string &message) {
        mediator->sendMessage(message, this);
    }

    void receiveMessage(const std::string &message) override {
        std::cout << "Colleague A received: " << message << std::endl;
    }
};

// 具体同事类B
class ConcreteColleagueB : public Colleague {
public:
    ConcreteColleagueB(Mediator *mediator) : Colleague(mediator) {}

    void sendMessage(const std::string &message) {
        mediator->sendMessage(message, this);
    }

    void receiveMessage(const std::string &message) override {
        std::cout << "Colleague B received: " << message << std::endl;
    }
};

// 具体中介者类
class ConcreteMediator : public Mediator {
private:
    std::unique_ptr<ConcreteColleagueA> colleagueA;
    std::unique_ptr<ConcreteColleagueB> colleagueB;

public:
    void setColleagueA(ConcreteColleagueA *colleague) {
        colleagueA.reset(colleague);
    }

    void setColleagueB(ConcreteColleagueB *colleague) {
        colleagueB.reset(colleague);
    }

    void sendMessage(const std::string &message, Colleague *colleague) override {
        if (colleague == colleagueA.get()) {
            colleagueB->receiveMessage(message);
        } else if (colleague == colleagueB.get()) {
            colleagueA->receiveMessage(message);
        }
    }
};

int main() {
    ConcreteMediator mediator;
    ConcreteColleagueA colleagueA(&mediator);
    ConcreteColleagueB colleagueB(&mediator);

    mediator.setColleagueA(&colleagueA);
    mediator.setColleagueB(&colleagueB);

    colleagueA.sendMessage("Hello from A");
    colleagueB.sendMessage("Hello from B");

    return 0;
}
  1. 抽象中介者类 (Mediator):

    • 定义了一个接口 sendMessage,用于传递消息。
  2. 抽象同事类 (Colleague):

    • 持有一个指向 Mediator 的指针。
    • 定义了一个纯虚函数 receiveMessage 用于接收消息。
  3. 具体同事类 (ConcreteColleagueAConcreteColleagueB):

    • 都继承自 Colleague 类,实现 receiveMessage 方法。
    • 添加了 sendMessage 方法,用于通过中介者发送消息。
  4. 具体中介者类 (ConcreteMediator):

    • 持有 ConcreteColleagueA 和 ConcreteColleagueB 的实例。
    • 实现 sendMessage 方法,根据发送消息的同事对象,将消息转发给另一个同事对象。
  5. main 函数:

    • 创建 ConcreteMediator 实例,并设置 ConcreteColleagueA 和 ConcreteColleagueB 实例。
    • 同事对象通过中介者发送和接收消息。

通过这种方式,同事对象之间的复杂依赖关系被简化到通过中介者进行交互,从而提高了系统的模块化和可维护性

posted @ 2024-06-14 18:11  白伟碧一些小心得  阅读(25)  评论(0编辑  收藏  举报