c++ 设计模式之桥接模式(Bridge)

作用:将抽象部份与它的实现部份分离,使它们都可以独立地变化。

将抽象(Abstraction)与实现(Implementation)分离,使得二者可以独立地变化。

桥接模式号称设计模式中最难理解的模式之一,关键就是这个抽象和实现的分离非常让人奇怪,大部分人刚看到这个定义的时候都会认为实现就是继承自抽象,那怎么可能将他们分离呢。

《大话设计模式》中就Bridge模式的解释:

手机品牌和软件是两个概念,不同的软件可以在不同的手机上,不同的手机可以有相同的软件,两者都具有很大的变动性。如果我们单独以手机品牌或手机软件为基类来进行继承扩展的话,无疑会使类的数目剧增并且耦合性很高,(如果更改品牌或增加软件都会增加很多的变动)两种方式的结构如下:



//所以将两者抽象出来两个基类分别是PhoneBrand和PhoneSoft,那么在品牌类中聚合一个软件对象的基类将解决软件和手机扩展混乱的问题,这样两者的扩展就相对灵活,剪短了两者的必要联系,结构图如下:



UML 图如下:


 

抽象基类及接口:

1、Abstraction::Operation():定义要实现的操作接口

2、AbstractionImplement::Operation():实现抽象类Abstaction所定义操作的接口,由其具体派生类ConcreteImplemenA、ConcreteImplemenA或者其他派生类实现。

3、在Abstraction::Operation()中根据不同的指针多态调用AbstractionImplement::Operation()函数。

理解:
Bridge用于将表示和实现解耦,两者可以独立的变化.在Abstraction类中维护一个AbstractionImplement类指针,需要采用不同的实现方式的时候只需要传入不同的AbstractionImplement派生类就可以了.

Bridge的实现方式其实和Builde十分的相近,可以这么说:本质上是一样的,只是封装的东西不一样罢了.两者的实现都有如下的共同点:

抽象出来一个基类,这个基类里面定义了共有的一些行为,形成接口函数(对接口编程而不是对实现编程),这个接口函数在Buildier中是BuildePart函数在Bridge中是Operation函数;

其次,聚合一个基类的指针,如Builder模式中Director类聚合了一个Builder基类的指针,而Brige模式中Abstraction类聚合了一个AbstractionImplement基类的指针(优先采用聚合而不是继承);

而在使用的时候,都把对这个类的使用封装在一个函数中,在Bridge中是封装在Director::Construct函数中,因为装配不同部分的过程是一致的,而在Bridge模式中则是封装在Abstraction::Operation函数中,在这个函数中调用对应的AbstractionImplement::Operation函数.就两个模式而言,Builder封装了不同的生成组成部分的方式,而Bridge封装了不同的实现方式.

桥接模式就将实现与抽象分离开来,使得RefinedAbstraction依赖于抽象的实现,这样实现了依赖倒转原则,而不管左边的抽象如何变化,只要实现方法不变,右边的具体实现就不需要修改,而右边的具体实现方法发生变化,只要接口不变,左边的抽象也不需要修改。

常用的场景
1.当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。如上面例子中手机品牌有2种变化因素,一个是品牌,一个是功能。

2.当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来,如上面例子中的通讯录和游戏,其实是可以共享的。

3.当我们考虑一个对象的多个变化因素可以动态变化的时候,考虑使用桥接模式,如上面例子中的手机品牌是变化的,手机的功能也是变化的,所以将他们分离出来,独立的变化。

优点
1.将实现抽离出来,再实现抽象,使得对象的具体实现依赖于抽象,满足了依赖倒转原则。

2.将可以共享的变化部分,抽离出来,减少了代码的重复信息。

3.对象的具体实现可以更加灵活,可以满足多个因素变化的要求。

缺点
1.客户必须知道选择哪一种类型的实现

代码如下“

// Implemement.hpp

#pragma  once 

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

using namespace  std;



class AbstractionImlement
{
public: 
	virtual ~AbstractionImlement()
	{
	
	}

	virtual void Operation() = 0;

protected:
	AbstractionImlement()
	{
	
	}
};

class ConcreteAbstractionImplemetA:public AbstractionImlement
{
public:
	ConcreteAbstractionImplemetA()
	{
	}
	~ConcreteAbstractionImplemetA()
	{
	
	}

	void Operation()
	{
		 cout << "通讯录 Operation" << endl;
	}

};


class ConcreteAbstractionImplemetB:public AbstractionImlement
{
public:
	ConcreteAbstractionImplemetB()
	{
	}
	~ConcreteAbstractionImplemetB()
	{
	
	}

	void Operation()
	{
		 cout << "软件  Operation" << endl;
	}

};

//Bridge.hpp

#pragma once 
#include"stdafx.h"
#include"Implement.hpp"
#include<iostream>

using namespace std;





class Abstraction
{
public:
	virtual  void Operation() = 0;

	virtual ~Abstraction()
	{
	
	}
protected:
	Abstraction()
	{
	
	}	


};

class RefinedAbstrctionA : public Abstraction
{
public:
	RefinedAbstrctionA(AbstractionImlement *Imp):m_Imp(Imp)
	{
	
	}
	~RefinedAbstrctionA()
	{
	
	}

	void Operation() 
	{
		 cout << "手机品牌 A::Operation" << endl;
		 m_Imp->Operation();
	}
private:
	AbstractionImlement* m_Imp;


};


class RefinedAbstrctionB:public Abstraction
{
public:
	RefinedAbstrctionB(AbstractionImlement *Imp):m_Imp(Imp)
	{
	
	}
	~RefinedAbstrctionB()
	{
	
	}
	void Operation()
	{
		 cout << "手机品牌B::Operation" << endl;
		 m_Imp->Operation();
	}
private:
	AbstractionImlement* m_Imp;

};

client:

// BridgeMode.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"Bridge.hpp"


int _tmain(int argc, _TCHAR* argv[])
{

	 AbstractionImlement* imp = new ConcreteAbstractionImplemetA();        //实现部分ConcreteAbstractionImplementA
     Abstraction* abs = new RefinedAbstrctionA(imp);                         //抽象部分RefinedAbstractionA
     abs->Operation();
 
     cout << "-----------------------------------------" << endl;
 
    AbstractionImlement* imp1 = new ConcreteAbstractionImplemetB();        //实现部分ConcreteAbstractionImplementB
     Abstraction* abs1 = new RefinedAbstrctionA(imp1);                        //抽象部分RefinedAbstractionA
     abs1->Operation();
 
     cout << "-----------------------------------------" << endl;
 
     AbstractionImlement* imp2 = new ConcreteAbstractionImplemetA();        //实现部分ConcreteAbstractionImplementA
     Abstraction* abs2 = new RefinedAbstrctionB(imp2);                        //抽象部分RefinedAbstractionB
     abs2->Operation();
 
     cout << "-----------------------------------------" << endl;
 
     AbstractionImlement* imp3 = new ConcreteAbstractionImplemetB();        //实现部分ConcreteAbstractionImplementB
     Abstraction* abs3 = new RefinedAbstrctionB(imp3);                        //抽象部分RefinedAbstractionB
     abs3->Operation();
 
     cout << endl;

	system("pause");
	return 0;
}

//运行结果



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
为了更好地理解桥接模式,我们可以考虑一个简单的例子:一个音乐播放器程序。该程序需要支持不同的音频格式(例如MP3,WAV,FLAC等),并且还需要能够在不同的操作系统上运行(例如Windows,MacOS,Linux等)。这个问题可以使用桥接模式来解决。 首先,我们需要定义音频播放器接口,包括播放,暂停和停止功能: ``` // 音频播放器接口 typedef struct _MediaPlayer MediaPlayer; struct _MediaPlayer { void (*play)(MediaPlayer*); void (*pause)(MediaPlayer*); void (*stop)(MediaPlayer*); }; ``` 然后,我们定义不同音频格式的播放器实现: ``` // MP3 播放器实现 typedef struct _MP3PlayerImpl MP3PlayerImpl; struct _MP3PlayerImpl { MediaPlayer super; // 为 MP3 文件格式添加特殊的功能 }; // WAV 播放器实现 typedef struct _WAVPlayerImpl WAVPlayerImpl; struct _WAVPlayerImpl { MediaPlayer super; // 为 WAV 文件格式添加特殊的功能 }; // FLAC 播放器实现 typedef struct _FLACPlayerImpl FLACPlayerImpl; struct _FLACPlayerImpl { MediaPlayer super; // 为 FLAC 文件格式添加特殊的功能 }; ``` 最后,我们定义操作系统的平台实现: ``` // Windows 操作系统平台实现 typedef struct _WindowsPlatformImpl WindowsPlatformImpl; struct _WindowsPlatformImpl { MediaPlayer* (*createMediaPlayer)(WindowsPlatformImpl*); // 为 Windows 操作系统添加特殊的功能 }; // MacOS 操作系统平台实现 typedef struct _MacOSPlatformImpl MacOSPlatformImpl; struct _MacOSPlatformImpl { MediaPlayer* (*createMediaPlayer)(MacOSPlatformImpl*); // 为 MacOS 操作系统添加特殊的功能 }; // Linux 操作系统平台实现 typedef struct _LinuxPlatformImpl LinuxPlatformImpl; struct _LinuxPlatformImpl { MediaPlayer* (*createMediaPlayer)(LinuxPlatformImpl*); // 为 Linux 操作系统添加特殊的功能 }; ``` 最后,我们可以使用桥接模式来组合不同的实现: ``` // 桥接模式 typedef struct _MediaPlayerBridge MediaPlayerBridge; struct _MediaPlayerBridge { MediaPlayer* (*createMediaPlayer)(MediaPlayerBridge*); void (*setPlatformImpl)(MediaPlayerBridge*, void*); void (*setAudioImpl)(MediaPlayerBridge*, void*); void* platformImpl; void* audioImpl; }; MediaPlayer* MediaPlayerBridge_createMediaPlayer(MediaPlayerBridge* bridge) { MediaPlayer* player = bridge->createMediaPlayer(bridge); return player; } void MediaPlayerBridge_setPlatformImpl(MediaPlayerBridge* bridge, void* impl) { bridge->platformImpl = impl; } void MediaPlayerBridge_setAudioImpl(MediaPlayerBridge* bridge, void* impl) { bridge->audioImpl = impl; } // Windows 平台的播放器 MediaPlayer* WindowsPlatformImpl_createMediaPlayer(WindowsPlatformImpl* impl) { MP3PlayerImpl* player = (MP3PlayerImpl*)malloc(sizeof(MP3PlayerImpl)); player->super.play = MP3Player_play; player->super.pause = MP3Player_pause; player->super.stop = MP3Player_stop; // 添加 Windows 平台特殊的实现 return (MediaPlayer*)player; } // MacOS 平台的播放器 MediaPlayer* MacOSPlatformImpl_createMediaPlayer(MacOSPlatformImpl* impl) { WAVPlayerImpl* player = (WAVPlayerImpl*)malloc(sizeof(WAVPlayerImpl)); player->super.play = WAVPlayer_play; player->super.pause = WAVPlayer_pause; player->super.stop = WAVPlayer_stop; // 添加 MacOS 平台特殊的实现 return (MediaPlayer*)player; } // Linux 平台的播放器 MediaPlayer* LinuxPlatformImpl_createMediaPlayer(LinuxPlatformImpl* impl) { FLACPlayerImpl* player = (FLACPlayerImpl*)malloc(sizeof(FLACPlayerImpl)); player->super.play = FLACPlayer_play; player->super.pause = FLACPlayer_pause; player->super.stop = FLACPlayer_stop; // 添加 Linux 平台特殊的实现 return (MediaPlayer*)player; } int main() { MediaPlayerBridge bridge; bridge.createMediaPlayer = NULL; bridge.setPlatformImpl = MediaPlayerBridge_setPlatformImpl; bridge.setAudioImpl = MediaPlayerBridge_setAudioImpl; bridge.platformImpl = NULL; bridge.audioImpl = NULL; // Windows 平台的 MP3 播放器 WindowsPlatformImpl windowsImpl; windowsImpl.createMediaPlayer = WindowsPlatformImpl_createMediaPlayer; bridge.setPlatformImpl(&bridge, &windowsImpl); MP3PlayerImpl mp3Impl; bridge.setAudioImpl(&bridge, &mp3Impl); MediaPlayer* player = MediaPlayerBridge_createMediaPlayer(&bridge); player->play(player); // MacOS 平台的 WAV 播放器 MacOSPlatformImpl macosImpl; macosImpl.createMediaPlayer = MacOSPlatformImpl_createMediaPlayer; bridge.setPlatformImpl(&bridge, &macosImpl); WAVPlayerImpl wavImpl; bridge.setAudioImpl(&bridge, &wavImpl); player = MediaPlayerBridge_createMediaPlayer(&bridge); player->play(player); // Linux 平台的 FLAC 播放器 LinuxPlatformImpl linuxImpl; linuxImpl.createMediaPlayer = LinuxPlatformImpl_createMediaPlayer; bridge.setPlatformImpl(&bridge, &linuxImpl); FLACPlayerImpl flacImpl; bridge.setAudioImpl(&bridge, &flacImpl); player = MediaPlayerBridge_createMediaPlayer(&bridge); player->play(player); return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值