文章目录
- 中介者模式
- 结构
- 实现
- 特点
中介者模式
为了有一个好的面向对象的设计,我们必须创建许多相互交互的类。如果不应用某些原则,最终的框架将以一团糟而告终,其中每个对象都依赖于许多其他对象才能运行。为了避免紧密耦合的框架,我们需要一种机制来促进对象之间的交互,其方式是对象不知道其他对象的存在。
对于那些对象之间存在复杂交互关系的系统,中介者模式(Mediator Pattern)提供了一种简单化复杂交互的解决方案。
中介模式定义了一个对象,该对象封装了一组对象如何交互。使用中介模式,对象之间的通信被封装在中介对象中。对象不再直接相互通信,而是通过中介器进行通信。这减少了通信对象之间的依赖性,从而减少了耦合。
用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
通过引入中介者来简化对象之间的复杂交互,中介者模式是“迪米特法则”的一个典型应用。
场景表单验证问题
假如在修改用户资料页,有许多表单组件(如:文本框、复选框、列表框、按钮等),某些表单可能会存在联动(如:地址级联菜单、提交后会验证所有表单并显示错误信息),以表单验证为例,如果要完成验证提示功能,你按钮类需要关联页面所有表单元素,随着控件增多维护非常困难,控件之间的耦合度非常高,如果有重复逻辑,也无法复用。
使用中介者模式,来停止组件直接的直接交流。将页面本身作为中介者,页面知道自己所有的子组件,不需要新增依赖关系。之前, 当用户点击按钮后, 它必须对所有表单元素数值进行校验。 而现在它的唯一工作是将点击事件通知给对页面。 收到通知后, 页面可以自行校验数值或将任务委派给各元素。这样一来, 按钮不再与多个表单元素相关联, 而仅依赖于页面类。
采用这种方式, 中介者模式让你能在单个中介者对象中封装多个对象间的复杂关系网。 类所拥有的依赖关系越少, 就越易于修改、 扩展或复用。
类比现实世界
交通拥挤的时候,通过交警来疏通。如果驾驶员直接相互协商车辆之间的行进顺序,那就是后果可能会打起来吧!
结构
在中介者模式结构图中包含如下几个角色:
- Mediator (中介者): 接口声明了与组件交流的方法, 但通常仅包括一个通知方法。 组件可将任意上下文 (包括自己的对象) 作为该方法的参数, 只有这样接收组件和发送者类之间才不会耦合。
- Component (组件):是各种包含业务逻辑的类。 每个组件都有一个指向中介者的引用, 该引用被声明为中介者接口类型。 组件不知道中介者实际所属的类, 因此你可通过将其连接到不同的中介者以使其能在其他程序中复用。
- Concrete Mediator (具体中介者):封装了多种组件间的关系。 具体中介者通常会保存所有组件的引用并对其进行管理, 甚至有时会对其生命周期进行管理。
组件并不知道其他组件的情况。 如果组件内发生了重要事件, 它只能通知中介者。 中介者收到通知后能轻易地确定发送者, 这或许已足以判断接下来需要触发的组件了。
对于组件来说, 中介者看上去完全就是一个黑箱。 发送者不知道最终会由谁来处理自己的请求, 接收者也不知道最初是谁发出了请求。
实现
// 抽象的中介机构classMediatorOrg{public:voidaddMember(Country*country);virtualvoiddeclare(string msg,Country*country,string name=string())=0;virtual~MediatorOrg(){}protected:map<string,Country*>m_countryMap;};#include<iostream>#include"Mediator.h"#include"Country.h"usingnamespacestd;// 基类的成员添加函数voidMediatorOrg::addMember(Country*country){m_countryMap.insert(make_pair(country->getName(),country));}// 在子类中重写发表声明的函数voidWorldGovt::declare(string msg,Country*country,string name){if(m_countryMap.find(name)!=m_countryMap.end()){string str=msg+"【来自: "+country->getName()+"】";m_countryMap[name]->setMessage(str);}}// 世界政府classCountry;classWorldGovt:publicMediatorOrg{public:voiddeclare(string msg,Country*country,string name=string())override;};#include<iostream>#include"Mediator.h"#include"Country.h"usingnamespacestd;// 基类的成员添加函数voidMediatorOrg::addMember(Country*country){m_countryMap.insert(make_pair(country->getName(),country));}// 在子类中重写发表声明的函数voidWorldGovt::declare(string msg,Country*country,string name){if(m_countryMap.find(name)!=m_countryMap.end()){string str=msg+"【来自: "+country->getName()+"】";m_countryMap[name]->setMessage(str);}}// 革命军classGeMingArmy:publicMediatorOrg{public:voiddeclare(string msg,Country*country,string name=string())override;};// 在子类中重写发表声明的函数voidGeMingArmy::declare(string msg,Country*country,string name){string str=msg+"【来自: "+country->getName()+"】";for(constauto&item:m_countryMap){if(item.second==country){continue;}item.second->setMessage(str);}}// 抽象国家类classCountry{public:Country(MediatorOrg*mediator):m_mediator(mediator){}// 发表声明virtualvoiddeclare(string msg,string country)=0;virtualvoidsetMessage(string msg)=0;virtualstringgetName()=0;virtual~Country(){}protected:MediatorOrg*m_mediator=nullptr;};#pragmaonce#include<string>#include<iostream>#include"Mediator.h"usingnamespacestd;// 抽象国家类classCountry{public:Country(MediatorOrg*mediator):m_mediator(mediator){}// 发表声明virtualvoiddeclare(string msg,string country)=0;virtualvoidsetMessage(string msg)=0;virtualstringgetName()=0;virtual~Country(){}protected:MediatorOrg*m_mediator=nullptr;};// 阿拉巴斯坦classAlabasta:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"阿拉巴斯坦得到的消息: "<<msg<<endl;}stringgetName()override{return"阿拉巴斯坦";}};// 德雷斯罗萨classDressrosa:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"德雷斯罗萨得到的消息: "<<msg<<endl;}stringgetName()override{return"德雷斯罗萨";}};// 露露西亚王国classLulusia:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"露露西亚得到的消息: "<<msg<<endl;}stringgetName()override{return"露露西亚";}};// 卡玛巴卡王国classKamabaka:publicCountry{public:usingCountry::Country;voiddeclare(string msg,string country)override{m_mediator->declare(msg,this,country);}voidsetMessage(string msg)override{cout<<"卡玛巴卡得到的消息: "<<msg<<endl;}stringgetName()override{return"卡玛巴卡";}};intmain(){// 世界政府WorldGovt*world=newWorldGovt;Alabasta*alaba=newAlabasta(world);Dressrosa*dresa=newDressrosa(world);// 世界政府添加成员world->addMember(alaba);world->addMember(dresa);// 世界政府成员发声alaba->declare("德雷斯罗萨倒卖军火, 搞得我国连年打仗, 必须给个说法!!!",dresa->getName());dresa->declare("天龙人都和我多弗朗明哥做生意, 你算老几, 呸!!!",alaba->getName());cout<<"======================================"<<endl;// 革命军GeMingArmy*geming=newGeMingArmy;Lulusia*lulu=newLulusia(geming);Kamabaka*kama=newKamabaka(geming);geming->addMember(lulu);geming->addMember(kama);lulu->declare("我草, 我的国家被伊姆毁灭了!!!",lulu->getName());deleteworld;deletealaba;deletedresa;deletegeming;deletelulu;deletekama;return0;}特点
中介者模式在事件驱动类软件中应用较为广泛,特别是基于GUI(Graphical User Interface,图形用户 界面)的应用软件,此外,在类与类之间存在错综复杂的关联关系的系统中,中介者模式都能得到较好的 应用。
当一些对象和其他对象紧密耦合以致难以对其进行修改时;当组件因过于依赖其他组件而无法在不同应用中复用时;当为了能在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,都可使用中介者模式。
主要优点
- 中介者模式简化了对象之间的交互,它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构。
- 中介者模式可将各同事对象解耦。中介者有利于各同事之间的松耦合,我们可以独立的改变和复用每一个同事和中介者,增加新的中介者和新的同事类都比较方便,更好地符合“开闭原则”。
- 可以减少子类生成,中介者将原本分布于多个对象间的行为集中在一起,改变这些行为只需生成新的中介者子类即可,这使各个同事类可被重用,无须对同事类进行扩展。
主要缺点
- 一段时间后, 中介者可能会演化成为上帝对象。
适用环境
- 当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。该模式让你将对象间的所有关系抽取成为一个单独的类, 以使对于特定组件的修改工作独立于其他 组件。
- 当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。应用中介者模式后,每个组件不再知晓其他组件的情况。 尽管这些组件无法直接交流, 但它们仍 可通过中介者对象进行间接交流。 如果你希望在不同应用中复用一个组件, 则需要为其提供一个新 的中介者类。
- 如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者 模式。由于所有组件间关系都被包含在中介者中, 因此你无需修改组件就能方便地新建中介者类以定义新 的组件合作方式。