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; }
-
抽象中介者类 (
Mediator
):- 定义了一个接口
sendMessage
,用于传递消息。
- 定义了一个接口
-
抽象同事类 (
Colleague
):- 持有一个指向
Mediator
的指针。 - 定义了一个纯虚函数
receiveMessage
用于接收消息。
- 持有一个指向
-
具体同事类 (
ConcreteColleagueA
和ConcreteColleagueB
):- 都继承自
Colleague
类,实现receiveMessage
方法。 - 添加了
sendMessage
方法,用于通过中介者发送消息。
- 都继承自
-
具体中介者类 (
ConcreteMediator
):- 持有
ConcreteColleagueA
和ConcreteColleagueB
的实例。 - 实现
sendMessage
方法,根据发送消息的同事对象,将消息转发给另一个同事对象。
- 持有
-
main
函数:- 创建
ConcreteMediator
实例,并设置ConcreteColleagueA
和ConcreteColleagueB
实例。 - 同事对象通过中介者发送和接收消息。
- 创建
通过这种方式,同事对象之间的复杂依赖关系被简化到通过中介者进行交互,从而提高了系统的模块化和可维护性