设计模式学习笔记--中介者模式
2016-05-09 18:43
351 查看
一.简介
今天来学习一下传说中的中介者模式。说到中介者,我们最容易想到的就是电话中继器,这里我们看看电话的演变过程吧。最早的电话只是两个通话的用户之间相连,这样的结构简单直接,操作最方便。但是随着使用电话的人数多了起来,为每两部电话之间架设一条线路很明显是不可能的,于是就有了电话中继器,记得以前经常看老电影里面,打电话的人要拿起电话,先打给接线员,说“给我接到XXX那”。没错,接线员就相当于中介者。在面向对象设计中,我们经常有很多类对象,对象之间需要交互,而如果对象过多,而每个对象之间都有可能交互的话,最简单的方式就是每个对象保存其他所有可能交互对象的引用,但是这样做有几个问题,第一,需要保存的内容过多,每个对象存一份,很明显是冗余,对象之间的耦合性太高,牵一发而动全身,如果新增一个类,所有之前的类都要修改。为了解决这个问题,中介者模式就应运而生了。下面看一下中介者模式的定义以及UML类图:
中介者模式(Mediator Pattern):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
简单解释一下UML类图,我们原本的对象在图中就相当于Colleague同事类,如果没有用中介者模式,他们每个具体的Collegue都需要保存其他所有对象的引用,UML图会灰常凌乱,而通过中介者Mediator,只有中介者自己保存所有对象的引用,而每个具体的同事类只需要和中介者建立关系,就可以和所有的其他同事类对象进行通信,这样大大降低了系统的耦合度。
二.中介者模式的例子
我们就拿电话的例子来看一下,有中介者和没有中介者的情况。
1.没有使用中介者模式的情况
// Design Pattern.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <string> #include <vector> using namespace std; //抽象电话类 class BasePhone { public: virtual void Call(int num) = 0; virtual void Answer() = 0; }; //移动电话 class MobilePhone : public BasePhone { private: vector<BasePhone*> m_phoneVec; string m_Name; public: MobilePhone(string name) : m_Name(name) { } //添加通讯录,或者说铺电话线更恰当 void Add(BasePhone* phone) { m_phoneVec.push_back(phone); } //根据号码打电话 virtual void Call(int num) override { cout << m_Name << "用手机打电话, "; m_phoneVec[num]->Answer(); } //接电话 virtual void Answer() override { cout << m_Name << "用手机接电话" << endl; } }; class TelePhone : public BasePhone { private: vector<BasePhone*> m_phoneVec; string m_Name; public: TelePhone(string name) : m_Name(name) { } //添加通讯录,或者说铺电话线更恰当 void Add(BasePhone* phone) { m_phoneVec.push_back(phone); } //根据号码打电话 virtual void Call(int num) override { cout << m_Name << "用座机打电话, "; m_phoneVec[num]->Answer(); //这里直接根据基类来处理了,如果有其他处理,耦合性更大 } //接电话 virtual void Answer() override { cout << m_Name << "用座机接电话" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { MobilePhone* phoneA = new MobilePhone("小明"); TelePhone* phoneB = new TelePhone("小刚"); MobilePhone* phoneC = new MobilePhone("小蔡"); //为每个对象和每个对象之间都建立联系 phoneA->Add(phoneA); phoneA->Add(phoneB); phoneA->Add(phoneC); phoneB->Add(phoneA); phoneB->Add(phoneB); phoneB->Add(phoneC); phoneC->Add(phoneA); phoneC->Add(phoneB); phoneC->Add(phoneC); phoneA->Call(1); phoneB->Call(2); phoneC->Call(0); system("pause"); return 0; }结果:
小明用手机打电话, 小刚用座机接电话
小刚用座机打电话, 小蔡用手机接电话
小蔡用手机打电话, 小明用手机接电话
请按任意键继续. . .
2.使用了中介者模式的情况
我们发现,每个电话都要与其他两个电话耦合,虽然这里我使用的是基类,可以降低一部分耦合,但是还是感觉代码不够优雅,我们不希望它们彼此之间联系过于密切,于是我们就添加一个中介者。// Design Pattern.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <iostream> #include <string> #include <vector> using namespace std; class BasePhone; //中介者基类 class BaseMediator { public: virtual void Call(int num) = 0; virtual void Add(BasePhone* phone) = 0; }; //抽象电话类 class BasePhone { protected: BaseMediator* m_Mediator; public: //现在我只需要增加一个中介者就可以了 void SetMediator(BaseMediator* mediator) { m_Mediator = mediator; } //通过中介者向其他电话发送信息 virtual void Call(int num) { m_Mediator->Call(num); } virtual void Answer() = 0; }; //电子电话中继器 class ElectricMediator : public BaseMediator { private: vector<BasePhone*> phoneVec; public: //登记电话 void Add(BasePhone* phone) override { phoneVec.push_back(phone); } //拨号 virtual void Call(int num) override { phoneVec[num]->Answer(); } }; //移动电话 class MobilePhone : public BasePhone { private: string m_Name; public: MobilePhone(string name) : m_Name(name) { } //根据号码打电话 virtual void Call(int num) override { cout << m_Name << "用手机打电话, "; BasePhone::Call(num); } //接电话 virtual void Answer() override { cout << m_Name << "用手机接电话" << endl; } }; class TelePhone : public BasePhone { private: string m_Name; public: TelePhone(string name) : m_Name(name) { } //根据号码打电话 virtual void Call(int num) override { cout << m_Name << "用座机打电话, "; BasePhone::Call(num); } //接电话 virtual void Answer() override { cout << m_Name << "用座机接电话" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { MobilePhone* phoneA = new MobilePhone("小明"); TelePhone* phoneB = new TelePhone("小刚"); MobilePhone* phoneC = new MobilePhone("小蔡"); BaseMediator* mediator = new ElectricMediator(); //向中介者中注册电话 mediator->Add(phoneA); mediator->Add(phoneB); mediator->Add(phoneC); //电话只保存中介者的引用就可以了 phoneA->SetMediator(mediator); phoneB->SetMediator(mediator); phoneC->SetMediator(mediator); phoneA->Call(1); phoneB->Call(2); phoneC->Call(0); system("pause"); return 0; }结果:
小明用手机打电话, 小刚用座机接电话
小刚用座机打电话, 小蔡用手机接电话
小蔡用手机打电话, 小明用手机接电话
请按任意键继续. .
.
三.中介者模式的总结
最后,我们来看一下中介者模式的优点,缺点以及使用时机:优点;
1)去除原来同事对象多对多的交互关系,用中介者和对象的一对多的关系代替,原来的网状结构被星型结构所代替。
2)中介者模式将复杂对象之间的耦合关系解除,新增对象时不需要更改原有代码,符合开放-封闭原则。
缺点:
中介者模式将大量对象的交互细节放在中介者中,中介者职责过重,难以维护。
使用时机:
当我们的系统中对象之间的引用关系呈网状,对象之间都需要相互引用,每个对象都需要引用其他对象时,我们就可以考虑使用中介者模式来重构系统。
相关文章推荐
- linux:磁盘的分割、检验、格式化与挂载
- 横竖屏切换时Activity 的生命周期
- php7.0 安装使用与性能监测
- HTML5 -- 网页框架bootstrap的简单使用
- 验证码 Captcha 之大插件
- ios网络请求特殊字符&处理
- 337. House Robber III (C++实现)
- iOS根据日期判断是刚刚、几分钟前、几小时前等的代码片段
- 8.samba server与client配置
- 毕业论文中的“题注”设置(经验五)
- 表格布局—计算器
- ♥POJ 1032-Parliament【数学】
- android登陆模块 联网登陆和离线登陆 类似微信离线登陆
- objc_msgSend()报错Too many arguments to function call ,expected 0,have3
- MySQL之EVENT定时任务用法小结
- 删除链表中重复的结点
- 搞不懂下面这个css样式加上:after之后就不起作用了
- 面向AMD64的文件xxx与项目的目标平台x86不兼容
- 代码训练营——泛型实例
- Mysql 5.5多实例部署步骤