图示:
模式Bridge的结构与对象适配器类似,但是Bridge模式的出发点不同:Bridge目的是将接口
部分和实现部分分离,从而对它们可以较为容易也相对独立的加以改变。而Adapter则意味着
改变一个已有对象的接口。
以下一些情况使用Bridge模式:
1、你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在
程序运行时刻实现部分应可以被选择或者切换。
2、类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge模式使你可以对不同的抽象
接口和实现部分进行组合,并分别对它们进行扩充。
3、对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
4、C++中你想对客户完全隐藏抽象的实现部分。在C++中,类的表示在类接口中是可见的。
代码Application类与IconWindow为外部接口类,它们从BaseWindow继承,都有接口方法DrawContents(),但完成的任务不同,这里的不同体现在两点,一点是作为接口函数,可以实现不同的接口功能,另一点是可以调用不同的实现类来完成所要定制的功能。
从代码中看出,通过字符串的切换便可达到调用不同的实现类,完成不同的功能,而实现类无需任何的改变。同样,实现类的改变也同样不会影响这里的接口部分。
原书中(指的那本《设计模式》)所述用一个factory工厂类来完成类的定义,将自动找寻到子类并new出来这样的功能封装在factory中,可惜我按书中的方法始终没成功,因此稍做了一些变通,或许使得实现类与接口类有一点的耦合,以后有时间再仔细研究一下。
以下为示例代码
// Bridge.h: interface for the Bridge class.
//
/**//**//**///////////////////////////////////////////////////////////////////////
#if !defined(AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_)
#define AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "BasicClass.h"
const MAX_PATH =250;
class View;
class WindowImp;
//Window的操作由WindowImp的接口定义。
//那么一个窗口怎样得到正确的WindowI子类的实例呢?在本例我们假设Window类具有
//职责,它的GetWindowImp操作负责从一个抽象工厂得到正确的实例,这个抽象工厂封
//装了所有窗口系统的细节。
class BaseWindow
...{
public:
BaseWindow()...{ _imp = 0; }
void SetClassName(const char* classname);
const char* GetClassNameA();
//requests handled by window
virtual void DrawContents()...{};
virtual void Open()...{}
protected:
WindowImp* GetWindowImp();
private:
char _className[MAX_PATH];
WindowImp* _imp;
};
//Window维护一个对WindowImp的引用,WindowImp抽象类定义了一个对底层窗口系统的接口
class WindowImp
...{
public:
virtual void DeviceRect(Coord, Coord, Coord, Coord) = 0;
virtual void DeviceText(const char*, Coord, Coord) = 0;
virtual void DeviceBitmap(const char*, Coord, Coord) = 0;
//lots more functions for drawing on windows
protected:
WindowImp()...{}
};
//Window的子类定义了应用程序可能用到的不同类型蝗窗口,如应用窗口,图标,对话框临时
//窗口以及工具箱的移动面板等。
//例如ApplicationWindow类将实现DrawContents 操作以绘制它所存储的View实例:
class ApplicationWindow: public BaseWindow
...{
public:
//
virtual void DrawContents();
};
//IconWindow中存储了它所显示的图标对应的位图名
//并且实现DrawContents操作将这个位图绘制在窗口上。
class IconWindow: public BaseWindow
...{
public:
//
virtual void DrawContents();
private:
const char* _bitmapName;
};
//具体的WindowImp子类可支持不同的窗口系统, XWindowImp子类支持XWindow窗口系统:
class XWindowImp: public WindowImp
...{
public:
XWindowImp()...{}
virtual void DeviceRect(Coord, Coord, Coord, Coord);
virtual void DeviceText(const char*, Coord, Coord) ;
virtual void DeviceBitmap(const char*, Coord, Coord);
//remainder of public interface
private:
//lots of X Window system-specific state, including:
// Display*_dpy;
// Drawable _winid;// window id;
// GC _gc;//window graphic context
};
//对于Presentation Manager(PM),
//我们定义PMWindowImp类
class PMWindowImp: public WindowImp
...{
public:
PMWindowImp()...{}
virtual void DeviceRect(Coord, Coord, Coord, Coord);
virtual void DeviceText(const char*, Coord, Coord) ;
virtual void DeviceBitmap(const char*, Coord, Coord);
//remainder of public interface
private:
//lots of PM window system-specific atate, including
//HPS _hps;
};
class WindowSystemFactory
...{
private:
static WindowSystemFactory* _instance;
public:
static WindowSystemFactory* Instance();
WindowImp* MakeWindowImp(const char* className);
};
#endif // !defined(AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_)
// Bridge.cpp: implementation of the Bridge class.
//
/**//**//**///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Bridge.h"
#include <string.h>
#include <tchar.h>
#include <wtypes.h>
#include <string>
using std::string;
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define abs(a) ((a) < 0) ? (-(a)) : (a)
/**//**//**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**//**//**///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**//**//**///////////////////////////////////////////////////////////////////////
void BaseWindow::SetClassName(const char* classname)
...{
strcpy(_className, classname);
}
const char* BaseWindow::GetClassNameA()
...{
return _className;
}
WindowImp* BaseWindow::GetWindowImp()
...{
const char* className = GetClassNameA();
if(_imp == 0)
...{
_imp = WindowSystemFactory::Instance()->MakeWindowImp(className);
}
return _imp;
}
void ApplicationWindow::DrawContents()
...{
SetClassName(_T("XWindowImp"));
WindowImp* imp = GetWindowImp();
if(imp != 0)
...{
imp->DeviceRect(0,0,0,0);
}
//GetView()->DrawOn(this);
}
void IconWindow::DrawContents()
...{
SetClassName(_T("PMWindowImp"));
WindowImp* imp = GetWindowImp();
if(imp != 0)
...{
imp->DeviceBitmap(_bitmapName, 0.0, 0.0);
}
}
void XWindowImp::DeviceRect(Coord x0, Coord y0, Coord x1, Coord y1)
...{
#pragma warning(disable: 4244)
int x = min(x0, x1);
int y = min(y0, y1);
int w = abs(x0 - x1);
int h = abs(y0 - y1);
printf("XWindowImp::DeviceRect ");
#pragma warning(disable: 4244)
// XDrawRectangele(_dpy, _winid, _gc, x, y, w, h);
}
void XWindowImp::DeviceText(const char*, Coord, Coord)
...{
printf("XWindowImp::Devicetext ");
}
void XWindowImp::DeviceBitmap(const char*, Coord, Coord)
...{
printf("XWindowImp::DeviceBitmap ");
}
void PMWindowImp::DeviceRect(Coord x0, Coord y0, Coord x1, Coord y1)
...{
#pragma warning (disable: 4244)
Coord left = min(x0, x1);
Coord right = max(x0, x1);
Coord bottom = min(y0, y1);
Coord top = max(y0, y1);
POINTL point[4];
point[0].x = left; point[0].y = top;
point[1].x = right; point[1].y = top;
point[2].x = right; point[2].y = bottom;
point[3].x = left; point[3].y = bottom;
printf("PMWindowmp::DeviceRect ");
// if(
// (GpiBeginPath(_hps, 1L) == false)
// || (GpiSetCurrentPosition(_hps, &point[3]) == false)
// || (GpiPolyLine(_hps, 4L, point) == GPI_ERROR)
// || (GpiEndPath(_hps) == false)
// )
// {
// //report error
// }
// else
// {
// GpistrokePath(_hps, 1L, 0L);
// }
}
void PMWindowImp::DeviceText(const char*, Coord, Coord)
...{
printf("PMWindowImp::Devicetext ");
}
void PMWindowImp::DeviceBitmap(const char*, Coord, Coord)
...{
printf("PMWindowImp::DeviceBitmap ");
}
/**//**//**///////////////////////////////////////////////////////////////////////////
WindowSystemFactory* WindowSystemFactory::_instance = NULL;
WindowSystemFactory* WindowSystemFactory::Instance()
...{
if(_instance == NULL)
...{
_instance = new WindowSystemFactory;
}
return _instance;
}
WindowImp* WindowSystemFactory::MakeWindowImp(const char* className)
...{
WindowImp* imp = NULL;
string strclassName = className;
if(strclassName == _T("PMWindowImp"))
imp = new PMWindowImp;
if(strclassName == _T("XWindowImp"))
imp = new XWindowImp;
return imp;
}
// testBridge.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Bridge.h"
int main(int argc, char* argv[])
...{
printf("Hello World! ");
ApplicationWindow apw;
IconWindow icw;
apw.DrawContents();
icw.DrawContents();
return 0;
}
//
/**//**//**///////////////////////////////////////////////////////////////////////
#if !defined(AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_)
#define AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "BasicClass.h"
const MAX_PATH =250;
class View;
class WindowImp;
//Window的操作由WindowImp的接口定义。
//那么一个窗口怎样得到正确的WindowI子类的实例呢?在本例我们假设Window类具有
//职责,它的GetWindowImp操作负责从一个抽象工厂得到正确的实例,这个抽象工厂封
//装了所有窗口系统的细节。
class BaseWindow
...{
public:
BaseWindow()...{ _imp = 0; }
void SetClassName(const char* classname);
const char* GetClassNameA();
//requests handled by window
virtual void DrawContents()...{};
virtual void Open()...{}
protected:
WindowImp* GetWindowImp();
private:
char _className[MAX_PATH];
WindowImp* _imp;
};
//Window维护一个对WindowImp的引用,WindowImp抽象类定义了一个对底层窗口系统的接口
class WindowImp
...{
public:
virtual void DeviceRect(Coord, Coord, Coord, Coord) = 0;
virtual void DeviceText(const char*, Coord, Coord) = 0;
virtual void DeviceBitmap(const char*, Coord, Coord) = 0;
//lots more functions for drawing on windows
protected:
WindowImp()...{}
};
//Window的子类定义了应用程序可能用到的不同类型蝗窗口,如应用窗口,图标,对话框临时
//窗口以及工具箱的移动面板等。
//例如ApplicationWindow类将实现DrawContents 操作以绘制它所存储的View实例:
class ApplicationWindow: public BaseWindow
...{
public:
//
virtual void DrawContents();
};
//IconWindow中存储了它所显示的图标对应的位图名
//并且实现DrawContents操作将这个位图绘制在窗口上。
class IconWindow: public BaseWindow
...{
public:
//
virtual void DrawContents();
private:
const char* _bitmapName;
};
//具体的WindowImp子类可支持不同的窗口系统, XWindowImp子类支持XWindow窗口系统:
class XWindowImp: public WindowImp
...{
public:
XWindowImp()...{}
virtual void DeviceRect(Coord, Coord, Coord, Coord);
virtual void DeviceText(const char*, Coord, Coord) ;
virtual void DeviceBitmap(const char*, Coord, Coord);
//remainder of public interface
private:
//lots of X Window system-specific state, including:
// Display*_dpy;
// Drawable _winid;// window id;
// GC _gc;//window graphic context
};
//对于Presentation Manager(PM),
//我们定义PMWindowImp类
class PMWindowImp: public WindowImp
...{
public:
PMWindowImp()...{}
virtual void DeviceRect(Coord, Coord, Coord, Coord);
virtual void DeviceText(const char*, Coord, Coord) ;
virtual void DeviceBitmap(const char*, Coord, Coord);
//remainder of public interface
private:
//lots of PM window system-specific atate, including
//HPS _hps;
};
class WindowSystemFactory
...{
private:
static WindowSystemFactory* _instance;
public:
static WindowSystemFactory* Instance();
WindowImp* MakeWindowImp(const char* className);
};
#endif // !defined(AFX_BRIDGE_H__C037F529_E449_4786_8DEE_D8293BF666D5__INCLUDED_)
// Bridge.cpp: implementation of the Bridge class.
//
/**//**//**///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Bridge.h"
#include <string.h>
#include <tchar.h>
#include <wtypes.h>
#include <string>
using std::string;
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define abs(a) ((a) < 0) ? (-(a)) : (a)
/**//**//**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**//**//**///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**//**//**///////////////////////////////////////////////////////////////////////
void BaseWindow::SetClassName(const char* classname)
...{
strcpy(_className, classname);
}
const char* BaseWindow::GetClassNameA()
...{
return _className;
}
WindowImp* BaseWindow::GetWindowImp()
...{
const char* className = GetClassNameA();
if(_imp == 0)
...{
_imp = WindowSystemFactory::Instance()->MakeWindowImp(className);
}
return _imp;
}
void ApplicationWindow::DrawContents()
...{
SetClassName(_T("XWindowImp"));
WindowImp* imp = GetWindowImp();
if(imp != 0)
...{
imp->DeviceRect(0,0,0,0);
}
//GetView()->DrawOn(this);
}
void IconWindow::DrawContents()
...{
SetClassName(_T("PMWindowImp"));
WindowImp* imp = GetWindowImp();
if(imp != 0)
...{
imp->DeviceBitmap(_bitmapName, 0.0, 0.0);
}
}
void XWindowImp::DeviceRect(Coord x0, Coord y0, Coord x1, Coord y1)
...{
#pragma warning(disable: 4244)
int x = min(x0, x1);
int y = min(y0, y1);
int w = abs(x0 - x1);
int h = abs(y0 - y1);
printf("XWindowImp::DeviceRect ");
#pragma warning(disable: 4244)
// XDrawRectangele(_dpy, _winid, _gc, x, y, w, h);
}
void XWindowImp::DeviceText(const char*, Coord, Coord)
...{
printf("XWindowImp::Devicetext ");
}
void XWindowImp::DeviceBitmap(const char*, Coord, Coord)
...{
printf("XWindowImp::DeviceBitmap ");
}
void PMWindowImp::DeviceRect(Coord x0, Coord y0, Coord x1, Coord y1)
...{
#pragma warning (disable: 4244)
Coord left = min(x0, x1);
Coord right = max(x0, x1);
Coord bottom = min(y0, y1);
Coord top = max(y0, y1);
POINTL point[4];
point[0].x = left; point[0].y = top;
point[1].x = right; point[1].y = top;
point[2].x = right; point[2].y = bottom;
point[3].x = left; point[3].y = bottom;
printf("PMWindowmp::DeviceRect ");
// if(
// (GpiBeginPath(_hps, 1L) == false)
// || (GpiSetCurrentPosition(_hps, &point[3]) == false)
// || (GpiPolyLine(_hps, 4L, point) == GPI_ERROR)
// || (GpiEndPath(_hps) == false)
// )
// {
// //report error
// }
// else
// {
// GpistrokePath(_hps, 1L, 0L);
// }
}
void PMWindowImp::DeviceText(const char*, Coord, Coord)
...{
printf("PMWindowImp::Devicetext ");
}
void PMWindowImp::DeviceBitmap(const char*, Coord, Coord)
...{
printf("PMWindowImp::DeviceBitmap ");
}
/**//**//**///////////////////////////////////////////////////////////////////////////
WindowSystemFactory* WindowSystemFactory::_instance = NULL;
WindowSystemFactory* WindowSystemFactory::Instance()
...{
if(_instance == NULL)
...{
_instance = new WindowSystemFactory;
}
return _instance;
}
WindowImp* WindowSystemFactory::MakeWindowImp(const char* className)
...{
WindowImp* imp = NULL;
string strclassName = className;
if(strclassName == _T("PMWindowImp"))
imp = new PMWindowImp;
if(strclassName == _T("XWindowImp"))
imp = new XWindowImp;
return imp;
}
// testBridge.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Bridge.h"
int main(int argc, char* argv[])
...{
printf("Hello World! ");
ApplicationWindow apw;
IconWindow icw;
apw.DrawContents();
icw.DrawContents();
return 0;
}