您的位置:首页 > 其它

阿Sam的设计模式学习笔记---- Bridge模式

2007-10-28 23:22 741 查看
1, 功能:
将抽象部分与它的实现部分分离,使它们都可以独立的变化。换言之,就是实现共同点与变化点的分离(主要是外部的变化),将变化点封装成类进行处理。
2, 基本思想:
将时间的抽象与行为分开,使对象的属性与方法之间耦合度降低。只需要分别继承抽象的属性接口和方法接口就可以任意的“变化”具体对象的属性和方法。
3, 适用情况
不希望在抽象和它的实现部分之间有一个固定的绑定关系。
Ÿ 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。Bridge模式可以对不同的抽象接口和实现部分进行组合,并分别对他们进行扩充。
Ÿ 对一个抽象的实现部分的修改对客户不产生影响,客户代码不必重新编译。
Ÿ 在C++中,类的表示在类接口中是可见的,Bridge方式对客户完全隐藏抽象的实现部分。
Ÿ 希望在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这点。
4, 结构



说明:
(1) Abstraction定义了抽象类的接口,它维护一个指向Implementor类型对象的指针;
(2) RefinedAbstraction实现Abstraction接口的方法;RefinedAbstraction类的对象才是真正要“Implemented”的对象;
(3) Implementor是实现类的接口,它不一定要求与Abstraction接口一致。一般来讲,Implementor接口仅提供基本操作,Abstraction定义的操作的具体实现通过Implementor接口的方法来实现。
(4) ConcreteImpementor接口实现了Implementor接口。
5, 举例
现在要设计一个绘图程序,可以画圆形和矩形。同时我们有两个不同版本的函数库,提供两套画图的实现(ShapeOne和ShapeTwo中分别调用两个库中的方法)。通常的实现方法,类的结构如下所示:



#include <iostream>
using namespace std;

// Draw with library 1
class CDrawLibOne
{
public:
void DrawCircle(){cout << "Draw circle with lib one" << endl;}
void DrawRectangle() {cout << "Draw rectangle with lib one" << endl;}
};
// Draw with library 2
class CDrawLibTwo
{
public:
void DrawCircle(){cout << "Draw circle with lib two" << endl;}
void DrawRectangle() {cout << "Draw rectangle with lib two" << endl;}
};

// CShapeOne class use library 1 to draw shapes
class CShapeOne
{
public:
virtual void Draw() = 0;
protected:
CDrawLibOne m_lib;
};
// CCircleOne and CRectangleOne class are derived from CShape class.
// They use CDrawLibOne to draw.
class CCircleOne : public CShapeOne
{
void Draw() {m_lib.DrawCircle();}
};
class CRectangleOne : public CShapeOne
{
void Draw() {m_lib.DrawRectangle();}
};
// CShapeTwo class use library 2 to draw shapes
class CShapeTwo
{
public:
virtual void Draw() = 0;
protected:
CDrawLibTwo m_lib;
};
// CCircleOne and CRectangleOne class are derived from CShape class.
// They use CDrawLibOne to draw.
class CCircleTwo : public CShapeTwo
{
void Draw() {m_lib.DrawCircle();}
};
class CRectangleTwo : public CShapeTwo
{
void Draw() {m_lib.DrawRectangle();}
};

// Define two global functions to draw with CShapeOne and CShapeTwo
void DrawOne(CShapeOne &s)
{
s.Draw();
}
void DrawTwo(CShapeTwo &s)
{
s.Draw();
}

// The client use above classes to draw
int main()
{
CCircleOne c1;
CCircleTwo c2;
CRectangleOne r1;
CRectangleTwo r2;

DrawOne(c1);
DrawOne(r1);
DrawTwo(c2);
DrawTwo(r2);
return 1;
}

上面的代码运行起来没有问题,但是非常不便于维护,尤其是由于某种原因要求程序发生变化时。可能的变化是:需要添加新的函数库或者需要画新的图形(比如说画三角形)。假如现在要画三角形,那么按照之前的设计方案,需要定义CTriangle,修改库文件(最痛苦的修改)DrawLibOne和DrawLibTwo,CShapeOne和CShapeTwo,添加画三角形的方法。上面的代码很小,如果库很复杂,类的结构也复杂,那么这种修改就是非常痛苦的。
用Bridge模式来实现,就简单清晰了,并且易于扩展。Bridge模式最重要就是把表示和实现分开。结构图如下:



#include <iostream>
#include “stdafx.h”
using namespace std;

// Draw with library 1
class CDrawLibOne
{
public:
void DrawCircle(){cout << “Draw circle with lib one” << endl;}
void DrawRectangle() {cout << “Draw rectangle with lib one” << endl;}
};
// Draw with library 2
class CDrawLibTwo
{
public:
void DrawCircle(){cout << “Draw circle with lib two” << endl;}
void DrawRectangle() {cout << “Draw rectangle with lib two” << endl;}
};
// Implementation interface for CShape
class CShapeImp
{
public:
virtual void DrawCircle() = 0;
virtual void DrawRectangle() = 0;
};
// Use Lib one to draw.
Class CShapeImpOne: public CShapeImp
{
public:
virtual void DrawCircle() {m_lib.DrawCircle();}
virtual void DrawRectangle() {m_lib.DrawRectangle();}
private:
CDrawLibOne m_lib;
};
// Use Lib two to draw.
Class CShapeImpTwo : public CShapeImp
{
public:
virtual void DrawCircle() {m_lib.DrawCircle();}
virtual void DrawRectangle() {m_lib.DrawRectangle();}
private:
CDrawLibTwo m_lib;
};

class CShape
{
public:
virtual void Draw() = 0;
protected:
CShapeImp * m_Imp;
};
class CCircle : public CShape
{
public:
CCircle(CShapeImp * imp) {m_Imp = imp;}
Virtual void Draw(){m_Imp->DrawCircle();}
};
class CRectangle : public CShape
{
public:
CRectangle(CShapeImp * imp) {m_Imp = imp;}
Virtual void Draw() {m_Imp->DrawRectangle();}
};

// Start Drawing
void main()
{
CShapeImpOne sImp1;
CShapeImpTwo sImp2;

// Draw with the Library 1
CCircle c1(&sImp1);
CRectangle r1(&sImp1);
C1.Draw();
R1.Draw();

// Draw with the Library 2
CCircle c2(&sImp2);
CRectangle r2(&sImp2);
C2.Draw();
R2.Draw();
Return;
}

上面的代码是Bridge的实现。如果我们要想再画三角形,我们只需要在原有库的基础之上,建立一个新库实现画三角形的方法。然后,针对新的库定义新的CShapeImp类以及我们要画的CTriangle类。这样不会修改原有的库和类。符合设计模式原则中的“开闭原则”:软件实体应当对扩展开放,对修改关闭。
6, 总结
未使用Bridge模式的结构中,所有的类都处于一维空间,在同一条轴线上。要用哪个库来画哪个图形,用函数表示就是:Draw = f(Shape);



使用Bridge模式结构中,把变化的部分和不变的部分分别列在两个正交的坐标轴上,形成二维坐标系统。在随机系统中,正交的两个序列相关性最小。因此,Bridge模式就剥离了实现和表现。用函数表示为:Draw = f(Shape, Imp)



7, 相关模式
Abstract Factory模式可以用来创建和配置一个特定的Bridge模式
Adapter模式用来帮助无关的类协同工作,它通常在系统设计完成后才会被使用;Bridge模式则是在系统开始时就被使用,它使得抽象接口和实现部分可以独立进行改变。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: