您现在的位置是:首页 >技术交流 >设计模式之桥接模式网站首页技术交流

设计模式之桥接模式

Leen 2024-09-20 12:01:06
简介设计模式之桥接模式

之前有时间的时候总是会读一下设计模式,但是总是觉得似懂非懂,当时记住了,没多久又忘记了,近来看了李建忠讲的设计模式,感觉有所收获。

首先要理解这个模式要解决什么问题:

在软件开发设计中,由于类封装的不合理,责任划分的不明确,使继承得到的具体子类数量急剧膨胀,也同时充斥着大量的重复代码。

桥接模式的主要用途就是 将抽象维度与实现维度去分离成两条线,再将两条线上的类进行组合,动态的实现所需要的功能。

接下来时代码演示,让我们更好的理解这个模式的作用。

假设现在有如下需求:

需要设计消息发送模块,模块又 登录,发送文字,发送图片接口

模块有精简版、标准版(执行具体动作前播放提示音)、完美版(执行具体动作前、后播放提示音)

这时候可能我们大脑中已经设计类的抽象结构了,可能如下

 具体代码:

class Messager {
public:
	Messager(){};
	virtual ~Messager(){};
	virtual int Login(string user_name, string pwd) = 0;
	virtual int SendText(string strText) = 0;
	virtual int SendImage(string strPath) = 0;

	virtual void PlaySound() = 0;
	virtual void DrawPicture() = 0;
	virtual void Connect() = 0;
	virtual void WriteText() = 0;
};

class PCMessagerBase : public Messager {
public:
	PCMessagerBase(){};
	virtual ~PCMessagerBase(){};
public:
	virtual int Login(string user_name, string pwd){
		return 0; 
	};
	virtual int SendText(string strText){ return 0; };
	virtual int SendImage(string strPath) { return 0; };
public:
	virtual void PlaySound(){ cout << "PC PlaySound" << endl; };
	virtual void DrawPicture(){ cout << "PC DrawPicture" << endl; };
	virtual void Connect(){ cout << "PC Connect" << endl; };
	virtual void WriteText(){ cout << "PC WriteText" << endl; };
};

class MobileMessagerBase : public Messager {
public:
	MobileMessagerBase(){};
	virtual ~MobileMessagerBase(){};
public:
	virtual int Login(string user_name, string pwd){
		return 0;
	};
	virtual int SendText(string strText){ return 0; };
	virtual int SendImage(string strPath) { return 0; };
public:
	virtual void PlaySound(){ cout << "Mobile PlaySound" << endl; };
	virtual void DrawPicture(){ cout << "Mobile DrawPicture" << endl; };
	virtual void Connect(){ cout << "Mobile Connect" << endl; };
	virtual void WriteText(){ cout << "Mobile WriteText" << endl; };
};

class PCMessagerLite : public PCMessagerBase {
public:
	PCMessagerLite(){};
	virtual ~PCMessagerLite(){};
public:
	virtual int Login(string user_name, string pwd){
		PCMessagerBase::Connect();
		return 0;
	};
	virtual int SendText(string strText){
		PCMessagerBase::WriteText();
		return 0;
	};
	virtual int SendImage(string strPath) {
		PCMessagerBase::DrawPicture();
		return 0;
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

class PCMessagerPerfect : public PCMessagerBase {
public:
	PCMessagerPerfect(){};
	virtual ~PCMessagerPerfect(){};
public:
	virtual int Login(string user_name, string pwd){
		PCMessagerBase::PlaySound();
		PCMessagerBase::Connect();
		PCMessagerBase::PlaySound();
		return 0;
	};
	virtual int SendText(string strText){
		PCMessagerBase::PlaySound();
		PCMessagerBase::WriteText();
		PCMessagerBase::PlaySound();
		return 0; 
	};
	virtual int SendImage(string strPath) { 
		PCMessagerBase::PlaySound();
		PCMessagerBase::DrawPicture();
		PCMessagerBase::PlaySound();
		return 0; 
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

class PCMessagerStandard : public PCMessagerBase {
public:
	PCMessagerStandard(){};
	virtual ~PCMessagerStandard(){};
public:
	virtual int Login(string user_name, string pwd){
		PCMessagerBase::PlaySound();
		PCMessagerBase::Connect();
		return 0;
	};
	virtual int SendText(string strText){
		PCMessagerBase::PlaySound();
		PCMessagerBase::WriteText();
		return 0;
	};
	virtual int SendImage(string strPath) {
		PCMessagerBase::PlaySound();
		PCMessagerBase::DrawPicture();
		return 0;
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

class MobileMessagerLite : public MobileMessagerBase {
public:
	MobileMessagerLite(){};
	virtual ~MobileMessagerLite(){};
public:
	virtual int Login(string user_name, string pwd){
		MobileMessagerBase::Connect();
		return 0;
	};
	virtual int SendText(string strText){
		MobileMessagerBase::WriteText();
		return 0;
	};
	virtual int SendImage(string strPath) {
		MobileMessagerBase::DrawPicture();
		return 0;
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

class MobileMessagerPerfect : public MobileMessagerBase {
public:
	MobileMessagerPerfect(){};
	virtual ~MobileMessagerPerfect(){};
public:
	virtual int Login(string user_name, string pwd){
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::Connect();
		MobileMessagerBase::PlaySound();
		return 0;
	};
	virtual int SendText(string strText){
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::WriteText();
		MobileMessagerBase::PlaySound();
		return 0;
	};
	virtual int SendImage(string strPath) {
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::DrawPicture();
		MobileMessagerBase::PlaySound();
		return 0;
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

class MobileMessagerStandard : public MobileMessagerBase {
public:
	MobileMessagerStandard(){};
	virtual ~MobileMessagerStandard(){};
public:
	virtual int Login(string user_name, string pwd){
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::Connect();
		return 0;
	};
	virtual int SendText(string strText){
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::WriteText();
		return 0;
	};
	virtual int SendImage(string strPath) {
		MobileMessagerBase::PlaySound();
		MobileMessagerBase::DrawPicture();
		return 0;
	};
public:
	virtual void PlaySound(){};
	virtual void DrawPicture(){};
	virtual void Connect(){};
	virtual void WriteText(){};
};

这时候我们会发现,如果我们再增加多一个平台的支持,就要增加4个类,而且此时不同平台的精简版、标准版,完美版,代码看起来非常的类似,重复。

桥接模式推荐我们将不同维度的变化去分离,然后让他们以动态组合的方式去实现功能

上面的代码中,我们会发现,Messager这个类有两个变为的维度,一个是平台实现(pc,mobile)另一个是业务抽象维度(轻量版、标准版、完美版),接下来我们将类按照这两个变换的维度去拆分成两个类,分别是 Messager, 以及它的平台实现MessagetImp

结构如下图所示:

具体代码如下:

namespace GOF_BRIDGE {
	

	class MessagerImp {
	public:
		MessagerImp(){};
		virtual ~MessagerImp(){};
		virtual void PlaySound() = 0;
		virtual void DrawPicture() = 0;
		virtual void Connect() = 0;
		virtual void WriteText() = 0;
	};

	class Messager {
	public:
		Messager(MessagerImp* pMI){ m_pMI = pMI; };
		virtual ~Messager(){};
		virtual int Login(string user_name, string pwd) = 0;
		virtual int SendText(string strText) = 0;
		virtual int SendImage(string strPath) = 0;
	protected:
		MessagerImp* m_pMI;
	};

	class MobileMessagerImp : public MessagerImp {
	public:
		MobileMessagerImp(){};
		virtual ~MobileMessagerImp(){};
	public:
		virtual void PlaySound(){ cout << "Mobile PlaySound" << endl; };
		virtual void DrawPicture(){ cout << "Mobile DrawPicture" << endl; };
		virtual void Connect(){ cout << "Mobile Connect" << endl; };
		virtual void WriteText(){ cout << "Mobile WriteText" << endl; };
	};

	class PCMessagerImp : public MessagerImp {
	public:
		PCMessagerImp(){};
		virtual ~PCMessagerImp(){};
	public:
		virtual void PlaySound(){ cout << "PC PlaySound" << endl; };
		virtual void DrawPicture(){ cout << "PC DrawPicture" << endl; };
		virtual void Connect(){ cout << "PC Connect" << endl; };
		virtual void WriteText(){ cout << "PC WriteText" << endl; };
	};



	class MessagerLite : public Messager {
	public:
		MessagerLite(MessagerImp* pMI) : Messager(pMI){};
		virtual ~MessagerLite(){};
	public:
		virtual int Login(string user_name, string pwd){
			m_pMI->Connect();
			return 0;
		};
		virtual int SendText(string strText){
			m_pMI->WriteText();
			return 0;
		};
		virtual int SendImage(string strPath) {
			m_pMI->DrawPicture();
			return 0;
		};
	public:
		virtual void PlaySound(){};
		virtual void DrawPicture(){};
		virtual void Connect(){};
		virtual void WriteText(){};
	};

	class MessagerPerfect : public Messager {
	public:
		MessagerPerfect(MessagerImp* pMI) : Messager(pMI){};
		virtual ~MessagerPerfect(){};
	public:
		virtual int Login(string user_name, string pwd){
			m_pMI->PlaySound();
			m_pMI->Connect();
			m_pMI->PlaySound();
			return 0;
		};
		virtual int SendText(string strText){
			m_pMI->PlaySound();
			m_pMI->WriteText();
			m_pMI->PlaySound();
			return 0;
		};
		virtual int SendImage(string strPath) {
			m_pMI->PlaySound();
			m_pMI->DrawPicture();
			m_pMI->PlaySound();
			return 0;
		};
	public:
		virtual void PlaySound(){};
		virtual void DrawPicture(){};
		virtual void Connect(){};
		virtual void WriteText(){};
	};

	class MessagerStandard : public Messager {
	public:
		MessagerStandard(MessagerImp* pMI) : Messager(pMI){};
		virtual ~MessagerStandard(){};
	public:
		virtual int Login(string user_name, string pwd){
			m_pMI->PlaySound();
			m_pMI->Connect();
			return 0;
		};
		virtual int SendText(string strText){
			m_pMI->PlaySound();
			m_pMI->WriteText();
			return 0;
		};
		virtual int SendImage(string strPath) {
			m_pMI->PlaySound();
			m_pMI->DrawPicture();
			return 0;
		};
	public:
		virtual void PlaySound(){};
		virtual void DrawPicture(){};
		virtual void Connect(){};
		virtual void WriteText(){};
	};

}

int _tmain(int argc, _TCHAR* argv[])
{
	Messager* pM = new PCMessagerPerfect;
	pM->Login("", "");


	GOF_BRIDGE::MessagerImp* pImp = new GOF_BRIDGE::PCMessagerImp();
	GOF_BRIDGE::Messager* pM1 = new GOF_BRIDGE::MessagerPerfect(pImp);
	pM1->Login("", "");

	system("pause");
	return 0;
}

此时 我们用7个类解决了 一开始需要9个类来解决的问题,更重要的时如果我们再增加多一个平台的支持,比如再增加一个Arm平台,就只要增加1个类(ArmMessagerImp),对比使用设计模式之前的代码需要增加4个类(ArmMessagerBase、ArmMessagerLite、ArmMessagerStandard、ArmMessagerPerfect)来说,无论是开发效率以及未来的可维护性来说,都是提高了很多~

看到了使用桥接模式带来的具体效果,感觉多这个模式的理解也加深,记忆也更加深刻了,你说对不对?

再对照一下桥接模式的结构图

是不是一下子就理解了呢?

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。