转载:
http://patmusing.blog.163.com/blog/static/13583496020100231174397/
Bridge模式又称为Handle/Body模式。
在软件系统中,经常面临着“某些结构复杂的对象”的创建工作,由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。大部分创建型模式,就是为了解决如何向“客户程序”隔离出“这些易变对象”,从而使得“依赖这些易变对象的客户程序”不随着需求的改变而改变。
事实上,上面的假设是经常面临剧烈变化的对象(实现细节b)拥有比较稳定一致的接口(抽象B)。现在的问题是,如果抽象B由于一些固有的原因也是面临着剧烈变化,那应该怎么办?
业务举例:
假如我们需要开发一个同时支持PC和手机的坦克游戏,游戏在PC和手机上的功能都一样,都有同样的类型,面临同样的功能需求变化,坦克有不同的型号:T50、T75和T90。(上面所言的抽象B就是坦克,现在抽象B即坦克本身也要变化了,需要PC上的坦克和手机上的坦克)
对于其中的坦克设计,我们可能很容易设计出来一个Tank的抽象基类,然后各种不同型号的Tank继承该基类:
// 抽象的坦克
class Tank
{
public:
virtual void shot() = 0; // 射击
virtual void run() = 0; // 行进
virtual void turn() = 0; // 转向
};
// 不同型号的坦克
class T50 : public Tank
{
...
};
class T75 : public Tank
{
...
};
class T90 : public Tank
{
...
};
由于PC机上和手机的图形绘制、声效、操作等具体实现有很大的差别,因此,对于各种型号的坦克,都要提供各种不同平台上的实现:
// PC机上的各型号坦克的实现
class PCT50 : public T50
{
...
};
class PCT75 : public T75
{
...
};
class PCT90 : public T90
{
...
};
// 手机上的各型号坦克的实现
class MobileT50 : public T50
{
...
};
class MobileT75 : public T75
{
...
};
class MobileT90 : public T90
{
...
};
这样以来就有会产生如上6个leaf或者terminal 类。
上面的设计思路会带来很多问题:有很多重复的代码,类的结果过于复杂,难以维护,以至于引入任何新的平台,比如TV上的Tank游戏,就会产生9个leaf或terminal类,显然会让整个类层级结构剧烈复杂化起来。
上述问题的结症:Tank类具有两个变化的维度,即“型号的变化”和“平台的变化”,Bridge设计模式就是利用面向对象的技术来使得Tank类型可以轻松地沿着“型号”和“平台”两个方向变化,而不引入额外的复杂度。
“Decouple an abstraction from its implementation so that the two can vary independently.” – GoF
下面是Bridge设计模式的类图:
另外一个被广泛用来说明Bridge设计模式的例子,就是GoF原著《Design Patterns, Elements of Reusable Object-Oriented Software》中讲到的在不同的图形系统下绘图的情况。
下面是C++实现代码示例:
// Bridge.h
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class PlatformImplementor;
class Tank
{
protected:
auto_ptr<PlatformImplementor> pli;
public:
Tank(auto_ptr<PlatformImplementor> plim) // plim不能与pli相同,因为如果相同,那么pli = plim;就必须写成:
{ // this->pli = pli;
pli = plim; // 而这会导致pli不知所指,这或许算是VS2005的一个bug
}
virtual string shot() = 0;
virtual string run() = 0;
virtual string turn() = 0;
public:
virtual ~Tank()
{
cout << "in the destructor of Tank..." << endl;
}
};
class PlatformImplementor
{
public:
virtual string draw_tank() = 0;
virtual string move_tank() = 0;
virtual string do_shot() = 0;
virtual string turn() = 0;
public:
virtual ~PlatformImplementor()
{
cout << "in the destructor of PlatformImplementor..." << endl;
}
};
// -------------------------------
class T50 : public Tank
{
public:
T50(auto_ptr<PlatformImplementor> plim) : Tank(plim)
{
string tmp_str = pli->draw_tank();
cout << "T50 - " << tmp_str << endl;
}
string run()
{
return "T50 - " + pli->move_tank();
}
string shot()
{
return "T50 - " + pli->do_shot();
}
string turn()
{
return "T50 - " + pli->turn();
}
~T50()
{
cout << "in the destructor of T50..." << endl;
}
};
class T75 : public Tank
{
public:
T75(auto_ptr<PlatformImplementor> plim) : Tank(plim)
{
string tmp_str = pli->draw_tank();
cout << "T75 - " << tmp_str << endl;
}
string run()
{
return "T75 - " + pli->move_tank();
}
string shot()
{
return "T75 - " + pli->do_shot();
}
string turn()
{
return "T75 - " + pli->turn();
}
~T75()
{
cout << "in the destructor of T75..." << endl;
}
};
class T90 : public Tank
{
public:
T90(auto_ptr<PlatformImplementor> plim) : Tank(plim)
{
string tmp_str = pli->draw_tank();
cout << "T90 - " << tmp_str << endl;
}
string run()
{
return "T90 - " + pli->move_tank();
}
string shot()
{
return "T90 - " + pli->do_shot();
}
string turn()
{
return "T90 - " + pli->turn();
}
~T90()
{
cout << "in the destructor of T90..." << endl;
}
};
// --------------------------
class PCPlatformImplementor : public PlatformImplementor
{
public:
string draw_tank()
{
return "PC platform: Draw a tank"; // 假定在这里画坦克
}
string move_tank()
{
return "PC platform: Move a tank"; // 假定在这里移动坦克
}
string do_shot()
{
return "PC platform: Fire the target"; // 假定在这里坦克开火
}
string turn()
{
return "PC platform: Turn direction"; // 假定在这里坦克转弯
}
public:
~PCPlatformImplementor()
{
cout << "in the destructor of PCPlatformImplementor..." << endl;
}
};
class MobilePlatformImplementor : public PlatformImplementor
{
public:
string draw_tank()
{
return "Mobile platform: Draw a tank";
}
string move_tank()
{
return "Mobile platform: Move a tank";
}
string do_shot()
{
return "Mobile platform: Fire the target";
}
string turn()
{
return "Mobile platform: Turn direction";
}
public:
~MobilePlatformImplementor()
{
cout << "in the destructor of MobilePlatformImplementor..." << endl;
}
};
// 测试代码:Bridge.cpp
#include "Bridge.h"
int main(int argc, char **argv)
{
auto_ptr<PlatformImplementor> pc_pli1(new PCPlatformImplementor);
T50 *pc_T50 = new T50(pc_pli1);
cout << pc_T50->turn() << endl;
cout << pc_T50->shot() << endl;
cout << pc_T50->turn() << endl;
// 由于auto_ptr的特性,pc_pli1到此已经无所指向,详见Tank类的构造函数
delete pc_T50;
cout << "--------------------------------------" << endl;
auto_ptr<PlatformImplementor> pc_pli2(new PCPlatformImplementor);
T75 *pc_T75 = new T75(pc_pli2);
cout << pc_T75->turn() << endl;
cout << pc_T75->shot() << endl;
cout << pc_T75->turn() << endl;
// 由于auto_ptr的特性,pc_pli2到此已经无所指向,详见Tank类的构造函数
delete pc_T75;
cout << "--------------------------------------" << endl;
auto_ptr<PlatformImplementor> pc_pli3(new PCPlatformImplementor);
T90 *pc_T90 = new T90(pc_pli3);
cout << pc_T90->turn() << endl;
cout << pc_T90->shot() << endl;
cout << pc_T90->turn() << endl;
// 由于auto_ptr的特性,pc_pli3到此已经无所指向,详见Tank类的构造函数
delete pc_T90;
cout << "--------------------------------------" << endl;
auto_ptr<PlatformImplementor> mo_pli1(new MobilePlatformImplementor);
T50 *mo_T50 = new T50(mo_pli1);
cout << mo_T50->turn() << endl;
cout << mo_T50->shot() << endl;
cout << mo_T50->turn() << endl;
// 由于auto_ptr的特性,mo_pli1到此已经无所指向
delete mo_T50;
cout << "--------------------------------------" << endl;
auto_ptr<PlatformImplementor> mo_pli2(new MobilePlatformImplementor);
T75 *mo_T75 = new T75(mo_pli2);
cout << mo_T75->turn() << endl;
cout << mo_T75->shot() << endl;
cout << mo_T75->turn() << endl;
// 由于auto_ptr的特性,mo_pli2到此已经无所指向
delete mo_T75;
cout << "--------------------------------------" << endl;
auto_ptr<PlatformImplementor> mo_pli3(new MobilePlatformImplementor);
T90 *mo_T90 = new T90(mo_pli3);
cout << mo_T90->turn() << endl;
cout << mo_T90->shot() << endl;
cout << mo_T90->turn() << endl;
// 由于auto_ptr的特性,mo_pli3到此已经无所指向,详见Tank类的构造函数
delete mo_T90;
return 0;
}
运行结果:
T50 - PC platform: Draw a tank
T50 - PC platform: Turn direction
T50 - PC platform: Fire the target
T50 - PC platform: Turn direction
in the destructor of T50...
in the destructor of Tank...
in the destructor of PCPlatformImplementor...
in the destructor of PlatformImplementor...
--------------------------------------
T75 - PC platform: Draw a tank
T75 - PC platform: Turn direction
T75 - PC platform: Fire the target
T75 - PC platform: Turn direction
in the destructor of T75...
in the destructor of Tank...
in the destructor of PCPlatformImplementor...
in the destructor of PlatformImplementor...
--------------------------------------
T90 - PC platform: Draw a tank
T90 - PC platform: Turn direction
T90 - PC platform: Fire the target
T90 - PC platform: Turn direction
in the destructor of T90...
in the destructor of Tank...
in the destructor of PCPlatformImplementor...
in the destructor of PlatformImplementor...
--------------------------------------
T50 - Mobile platform: Draw a tank
T50 - Mobile platform: Turn direction
T50 - Mobile platform: Fire the target
T50 - Mobile platform: Turn direction
in the destructor of T50...
in the destructor of Tank...
in the destructor of MobilePlatformImplementor...
in the destructor of PlatformImplementor...
--------------------------------------
T75 - Mobile platform: Draw a tank
T75 - Mobile platform: Turn direction
T75 - Mobile platform: Fire the target
T75 - Mobile platform: Turn direction
in the destructor of T75...
in the destructor of Tank...
in the destructor of MobilePlatformImplementor...
in the destructor of PlatformImplementor...
--------------------------------------
T90 - Mobile platform: Draw a tank
T90 - Mobile platform: Turn direction
T90 - Mobile platform: Fire the target
T90 - Mobile platform: Turn direction
in the destructor of T90...
in the destructor of Tank...
in the destructor of MobilePlatformImplementor...
in the destructor of PlatformImplementor...
上述实现代码中各个类和Bridge模式中的各个类之间的对应关系:
Tank < ------ > Abstraction
T50、T75和T90 < ------ > RefinedAbstraction
PlatformImplementor < ------ > Implementor
PCPlatformImplementor < ------ > ConcreteImplementorA
MobilePlatformImplementor < ------ > ConcreteImplementorB
前面讲到的Adapter模式(对象适配器形式),从UML的角度来看,也可以画成:
因为Adapter中包含了一个Adaptee对象,这是一个聚合或者组合的关系。而且也是在Adapter的request方法中调用了Adaptee对象中的方法,从这个角度而言,Adapter模式和Bridge模式是非常类似的。
但是,他们之间有本质的区别:
1. 在Adapter模式中,Adaptee本身往往已经是一个具体的、已经存在的类。在Bridge模式中,Implementor则是一个抽象类或者接口;
2. 在Adapter模式中,Adapter类也是一个具体的类。在Bridge模式中,Abstraction则是一个抽象类;
3. 在Adapter模式中,Adapter类派生于一个抽象类/接口(客户程序所期望的)。在Bridge模式中,Abstraction类则不存在这样的情况。
4. 最本质同时也是最重要的区别是,它们的意图是不同的。