范例一:
#include <iostream> #include <thread> #ifdef _DEBUG //只在Debug(调试)模式下 #ifndef DEBUG_NEW #define DEBUG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__) //重新定义new运算符 #define new DEBUG_NEW #endif #endif using namespace std; //#pragma warning(disable : 4996) class Image { public: virtual ~Image() {}; void draw(const char *pfilename) { int len = 1; char* data = parsefile(pfilename, len); /*下面用于显示读取到的图片格式,不同的操作系统显示不一样*/ if(len > 0) { //模拟代码 cout << "显示缓冲区中的图像数据" << endl; } } /*该函数用于读取指定格式(比如png,jpg,bmp)*到一个缓存当中 不同格式的图片读取方式不一样,并且读取方式与操作系统平台无关*/ virtual char* parsefile(const char* pfilename, int &len) = 0; }; class Image_png :public Image { public: char* parsefile(const char* pfilename, int& len) { //...模拟代码 cout << "开始分析png文件中的数据并将分析结果放到缓存中\n"; return nullptr; } }; class Image_jpg :public Image { public: char* parsefile(const char* pfilename, int& len) { //...模拟代码 cout << "开始分析jpg文件中的数据并将分析结果放到缓存中\n"; return nullptr; } }; class Image_bmp :public Image { public: char* parsefile(const char* pfilename, int& len) { //...模拟代码 cout << "开始分析bmp文件中的数据并将分析结果放到缓存中\n"; return nullptr; } }; int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); Image* p = new Image_png(); p->draw("c:\\a.png"); return 0; }
像以上的范例当中,如果再引入不同的操作系统的话,他们之间的关系可能会变成如下所示。
缺点就是由于类与类之间的这种继承的关系会引入很多子类对象,后面再需要扩展的时候就不好维护了。
下面我们根据范例一进行改造一下,把类与类之间的关系有继承关系改成委托与组合关系。
委托与组合关系的话,他们采用的不是继承关系,而是在一个类当中包含另一个类的指针变量。
范例二:
#include <iostream> #include <thread> using namespace std; class ImageOS { public: virtual void draw(char* pData, int iLen) = 0; virtual ~ImageOS() {} }; class ImageOS_Windows :public ImageOS { public: virtual void draw(char* pData, int iLen) { //模拟代码 cout << "在Windows操作系统下显示缓冲区中的图像数据\n" << endl; } }; class ImageOS_Linux :public ImageOS { public: virtual void draw(char* pData, int iLen) { //模拟代码 cout << "在Linux操作系统下显示缓冲区中的图像数据\n" << endl; } }; class ImageOS_Mac :public ImageOS { public: virtual void draw(char* pData, int iLen) { //模拟代码 cout << "在Mac操作系统下显示缓冲区中的图像数据\n" << endl; } }; class ImageFormat { public: ImageFormat(ImageOS* pimgos) :m_pImgOS(pimgos) {} /*纯虚函数,有子类定义实现部分*/ virtual void parsefile(const char* pfilename) = 0; virtual ~ImageFormat() {} protected: ImageOS* m_pImgOS; //委托 }; class Image_png:public ImageFormat { public: Image_png(ImageOS* pimgos) :ImageFormat(pimgos){} void parsefile(const char* pfilename) { //模拟代码 cout << "读取png格式的内容到缓冲区当中\n" << endl; char* p = nullptr; int len = 0; m_pImgOS->draw(p, len); } }; class Image_jpg :public ImageFormat { public: Image_jpg(ImageOS* pimgos) :ImageFormat(pimgos) {} void parsefile(const char* pfilename) { //模拟代码 cout << "读取jpg格式的内容到缓冲区当中\n" << endl; char* p = nullptr; int len = 0; m_pImgOS->draw(p, len); } }; class Image_bmp :public ImageFormat { public: Image_bmp(ImageOS* pimgos) :ImageFormat(pimgos) {} void parsefile(const char* pfilename) { //模拟代码 cout << "读取bmp格式的内容到缓冲区当中\n" << endl; char* p = nullptr; int len = 0; m_pImgOS->draw(p, len); } }; int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); ImageOS* p_os = new ImageOS_Mac(); ImageFormat* p_format = new Image_bmp(p_os); p_format->parsefile("c:\\a.bmp"); delete p_os; delete p_format; return 0; }
如果要是再扩展一个新的操作系统,引入的子类对象是不是减少了?
引入桥接(Bridge)模式
不同维度的独立变化,才是能够顺利使用桥接模式的前提。
定义:将抽象部分与它的实现部分分离,使他们都可以独立地变化和扩展。
抽象部分:一般指业务功能,比如ImageFormat类。
实现部分:一般指具体平台实现,比如ImageOS类。
角色:
(a)Abstraction(抽象部分相关接口):ImageFormat类
(b)RefinedAbstraction(扩充抽象部分接口):Image_png、Image_jpg、Image_bmp类。
©Implementor(实现部分相关接口):ImageOS类
(d)ConcreteImplementor(实现部分具体类):ImageOS_Windows、ImageOS_Linux、ImageOS_Mac类。