《二十三种设计模式》 第三篇 “中介者模式” (C++实现)

定义:

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

简单点来说,将原来两个直接引用或者依赖的对象拆开,在中间加入一个‘中介’对象,使得两头的对象分别和‘中介’对象引用或者依赖。

中介者模式的组成部分:

种类说明
抽象中介者模式抽象中介者角色定义统一的接口用于各同事角色之间的通信;
具体中介者角色具体中介者角色通过协调各同事角色实现协作行为。为此它要知道并引用各个同事角色;
同事角色每一个同事角角色都知道对应的具体中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。

中介者模式的特点:

MVC模式也算是中介者模式在框架设计中的一个应用,那么MVC的控制层便是位于表现层与模型层之间的中介者。但是由于中介者模式在定义上比较松散,在结构上和观察者模式、命令模式十分相像;而应用目的又与结构模式“门面模式”有些相似,所以要注意区分它们之间的异同。

① 在结构上看,中介者模式与观察者模式、命令模式都添加了中间对象,只是中介者去掉了后两者在行为上的方向。因此中介者的应用可以仿照后两者的例子去写。

但是观察者模式、命令模式中的观察者、命令都是被客户所知的,具体哪个观察者、命令的应用都是由客户来指定的;而大多中介者角色对于客户程序却是透明的。

② 从目的上看,中介者模式与观察者模式、命令模式没有任何关系,倒是与前面讲过的门面模式有些相似。但是门面模式是介于客户程序与子系统之间的,而中介者模式是介于子系统与子系统之间的。

门面模式与中介者模式的区别:

门面模式是将原有的复杂逻辑提取到一个统一的接口,简化客户对逻辑的使用。它是被客户所感知的,而原有的复杂逻辑则被隐藏了起来。而中介者模式的加入并没有改变客户原有的使用习惯,它是隐藏在原有逻辑后面的,使得代码逻辑更加清晰可用。

中介者模式的优点:

  1. 使用中介者模式最大的好处就是将同事角色解耦。这带来了一系列的系统结构改善:提高了原有系统的可读性、简化原有系统的通信协议——将原有的多对多变为一对多、提高了代码的可复用性等等。
  2. 中介者角色集中了太多的责任,所有有关的同事对象都要由它来控制,所以不注意控制代码的规模极易引发其他问题。


通过以上的说明不知道有没有听懂呢?不懂没关系,下面我再通俗的讲一遍。

中介者模式实际上就是一个中介人,以我们生活上为例,房产中介,租房中介,招聘中介等等,两边的人通过中介去联系,获取对方所需要的,这就是中介者模式。

中介者模式一般用于后端与后端的联系,子系统与子系统的联系。而不能用于前后与后端(外观模式用于前端与后端的联系)。

那为什么要使用中介者模式呢?

比如我们要去买房,我们干嘛不直接去找销售方去购买,而要找到中介,还被赚取中间商差价呢?
如下图:
在这里插入图片描述
买家和买家直接进行交际,这样不就更加快捷吗?

事实是这样,但是!

大家有没有看到图片中,五花八乱,如果不是我用不同的颜色画出来,根本分不清楚谁和谁了,而且,这样着做,还会有牵一发而动全身的风险(例如:其中一个买家或者卖家出了问题,那么就会牵涉到所有人)!不利于后期维护(紧耦合)。

那么,如果我们在中间加上一个中介者会怎么样呢?

在这里插入图片描述

大家看到没,是不是简明多了,谁也不会牵涉到谁了,即使有其中一方出了问题,完全不需要动其他方面的代码,只需要修改一下中介者中得代码就行了,是不是效率就高很多了(松耦合)!
这就是中介者模式的奥妙!!!



不知道上面说的看懂了没有呢?不懂得可以回去看多几遍,重在理解!

下面我们以微信作为中介者为例子,以代码方式在讲解一遍,相信大家会搞懂的!

以故事引入主题:
话说盘古开天辟地后,诞生了世间万物,其中就有神仙和凡人,还有微信。一天,织女下凡玩耍,被正在耕田的牛郎看见了,牛郎那是一见钟情呀。于是呼,牛郎费尽心机,终于追到了织女,过上了“你来耕田我织衣”的生活!但是,好景不长,被岳母王母娘娘知道了,于是牛郎和织女便强行分离了。牛郎见不到织女了,终日以泪洗脸,但就在这时,我们的主角“微信”登场了!牛郎虽然无法直接与织女见面,但是他们可以使用微信的视频聊天见面呀。日复一日,年复一年,他们都是只能以微信视频聊天见面,就连喜鹊都懒得去搭桥了。最终,还是感动了王母娘娘,准许了他们相见。全剧终!
(以上故事纯属瞎扯,如有雷同纯属巧合)

我们通过故事可以知道,牛郎和织女本来是生活交织在一起的,但是,由于“紧耦性”太强,出现了许多问题,最终被岳母分开了。所以为了还能见面,他们使用了“中介”微信视频通话进行见面。

看到了没有,这就是中介者模式的运用!!!

要注重以“自然语言去理解”!

在写代码之前,先看一下中介者模式的UML类图吧!
UML中介者模式类图

其中中介和人类都是抽象类,而微信和牛郎和织女都是具体类!

好了明白了这些,让我们看代码吧:

为了使代码更加分明,我们把所有类都分开文件来写:

ZhongJieZhe.h - 抽象类

#pragma once

class DanShen;	// 类声明

// 抽象类
class ZhongJieZhe {
public:
	virtual void Send(const char* m_name, DanShen *danShen) = 0;	// 转发消息
};

BG_ZhongJie.h - 具体类 中介(微信)

#pragma once

#include "ZhongJieZhe.h"
#include "DanShenBoy.h"
#include "DanShenGirl.h"

class DanShen;	// 类声明

// 具体类----------------->继承与抽象类
class BG_ZhongJie : public ZhongJieZhe {
public:
	BG_ZhongJie() : boy(NULL), girl(NULL) { }	// 默认初始化值为NULL

	// 中介(微信)转发消息
	void Send(const char *message, DanShen *danShen);

	void setBoy(DanShen *danShen);	// 在中介中注册
	void setGirl(DanShen *danShen); // 在中介中注册

private:
	// 中介(微信)需要知道所有的客户
	DanShenBoy *boy;
	DanShenGirl *girl;
};

BG_ZhongJie.cpp - “微信”方法的具体实现

#include <iostream>
#include "BG_ZhongJie.h"


void BG_ZhongJie::Send(const char *message, DanShen *danShen) {
	
	// 判断合法性
	if (!message || !danShen) {
		exit(-1);
	}

	// 判断是谁发来的消息,进而对应转发
	if (danShen == boy) {
		cout << "中介收到来自 单身男 的消息:【" << message << "】,准备发给 单身女~" << endl;
		girl->Notify(message);
	} else {
		cout << "中介收到来自 单身女 的消息:【" << message << "】,准备发给 单身男~" << endl;
		boy->Notify(message);
	}
}



// 注册
void BG_ZhongJie::setBoy(DanShen *danShen) {
	boy = dynamic_cast<DanShenBoy*>(danShen);	// dynamic_cast 将父类对象转换为子类对象
}


// 注册
void BG_ZhongJie::setGirl(DanShen *danShen) {
	girl = dynamic_cast<DanShenGirl*>(danShen);	// dynamic_cast 将父类对象转换为子类对象
}

DanShen.h - 抽象类(人类)

#pragma once

#include <iostream>
#include <string>
#include "ZhongJieZhe.h"


using namespace std;

// 抽象类
class DanShen {
public:											// 一种赋值类成员变量的方式
	DanShen(ZhongJieZhe *zhongJie, string name) : zhongJie(zhongJie), name(name) { }

	virtual void Send(const char *message) = 0;

protected:
	ZhongJieZhe *zhongJie;	// 中介
	string name;			// 客户的姓名
};

DanShenBoy.h - 牛郎

#pragma once

#include "DanShen.h"

// 具体类
class DanShenBoy : public DanShen {
public:											// 一种赋值类成员变量的方式
	DanShenBoy(ZhongJieZhe * zhongJie, string name) : DanShen(zhongJie, name) { }

	// 发送消息给中介
	void Send(const char *message);

	// 收到中介发来的消息
	void Notify(const char *message);
};

DanShenBoy.cpp - 牛郎具体方法实现

#include "DanShenBoy.h"

// 把信息发送给中介
void DanShenBoy::Send(const char *message) {
	zhongJie->Send(message, this);
}


// 把收到的消息显示出来
void DanShenBoy::Notify(const char *message) {
	cout << name << "收到消息:" << message << endl;
}

DanShenGirl.h - 织女

#pragma once

#include "DanShen.h"

// 具体类
class DanShenGirl : public DanShen {
public:												// 一种赋值类成员变量的方式
	DanShenGirl(ZhongJieZhe * zhongJie, string name) : DanShen(zhongJie, name) { }

	// 发送消息给中介
	void Send(const char *message);

	// 收到中介发来的消息
	void Notify(const char *message);
};

DanShenGirl.cpp - 织女具体方法实现

#include "DanShenGirl.h"

// 把信息发送给中介
void DanShenGirl::Send(const char *message) {
	zhongJie->Send(message, this);
}


// 把收到的消息显示出来
void DanShenGirl::Notify(const char *message) {
	cout << name << "收到消息:" << message << endl;
}

main.cpp - 主方法

#include "BG_ZhongJie.h"

int main(void) {
	BG_ZhongJie*zj = new BG_ZhongJie();					// 定义中介
	DanShen *niuLang = new DanShenBoy(zj, "牛郎");		// 定义牛郎
	DanShen *zhiNv = new DanShenGirl(zj, "织女");		// 定义织女

	// 牛郎和织女在中介中注册
	zj->setBoy(niuLang);
	zj->setGirl(zhiNv);

	// 牛郎发送消息给中介
	niuLang->Send("今晚老地方见!");

	cout << endl;

	// 织女发送消息给中介
	zhiNv->Send("好,准时到!");

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述

代码中都有注释,相信也会能看得懂!
不懂的多看几次!


总结:

注重理解中介者模式的思想(通过我上面举的例子),再来研究代码!

记得从“自然语言”去理解!

上面代码中提到的“注册”的意思是:得先告诉中介你是谁,中介才能帮你转发!
差不多这样的意思!

如果有一个类发生了改变,不需要变动其他地方,只需要改动中介里的Send方法就行了!

void BG_ZhongJie::Send(const char *message, DanShen *danShen) {
	
	// 判断合法性
	if (!message || !danShen) {
		exit(-1);
	}

	// 判断是谁发来的消息,进而对应转发
	if (danShen == boy) {
		cout << "中介收到来自 单身男 的消息:【" << message << "】,准备发给 单身女~" << endl;
		girl->Notify(message);
	} else {
		cout << "中介收到来自 单身女 的消息:【" << message << "】,准备发给 单身男~" << endl;
		boy->Notify(message);
	}
}

中介者模式的精华之处也在这里是现实了!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值