都昌县2014年县委常委:C++实现Structural - Bridge模式

来源:百度文库 编辑:九乡新闻网 时间:2024/05/04 04:21:05

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

#include

#include

using namespace std;

 

class PlatformImplementor;

 

class Tank

{

protected:

         auto_ptr pli;

 

public:

         Tank(auto_ptr 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 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 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 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 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 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 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 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 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 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.       最本质同时也是最重要的区别是,它们的意图是不同的。