积木

No sub title

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  140 Posts :: 1 Stories :: 11 Comments :: 0 Trackbacks

常用链接

留言簿(1)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

转载:http://patmusing.blog.163.com/blog/static/13583496020100231174397/


Bridge
模式又称为Handle/Body模式。

9. C++实现Structural - Bridge模式 - 玄机逸士 - 玄机逸士博客

在软件系统中,经常面临着某些结构复杂的对象的创建工作,由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。大部分创建型模式,就是为了解决如何向客户程序隔离出这些易变对象,从而使得依赖这些易变对象的客户程序不随着需求的改变而改变。

事实上,上面的假设是经常面临剧烈变化的对象(实现细节b)拥有比较稳定一致的接口(抽象B)。现在的问题是,如果抽象B由于一些固有的原因也是面临着剧烈变化,那应该怎么办?

业务举例:

假如我们需要开发一个同时支持PC和手机的坦克游戏,游戏在PC和手机上的功能都一样,都有同样的类型,面临同样的功能需求变化,坦克有不同的型号:T50T75T90(上面所言的抽象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

{

...

};

这样以来就有会产生如上6leaf或者terminal 类。

上面的设计思路会带来很多问题:有很多重复的代码,类的结果过于复杂,难以维护,以至于引入任何新的平台,比如TV上的Tank游戏,就会产生9leafterminal类,显然会让整个类层级结构剧烈复杂化起来。

上述问题的结症:Tank类具有两个变化的维度,即型号的变化平台的变化Bridge设计模式就是利用面向对象的技术来使得Tank类型可以轻松地沿着型号平台两个方向变化,而不引入额外的复杂度。

“Decouple an abstraction from its implementation so that the two can vary independently.” – GoF

下面是Bridge设计模式的类图:

9. C++实现Structural - 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

T50T75T90 < ------ > RefinedAbstraction

PlatformImplementor < ------ > Implementor

PCPlatformImplementor < ------ > ConcreteImplementorA

MobilePlatformImplementor < ------ > ConcreteImplementorB

前面讲到的Adapter模式(对象适配器形式),从UML的角度来看,也可以画成:

9. C++实现Structural - Bridge模式 - 玄机逸士 - 玄机逸士博客

因为Adapter中包含了一个Adaptee对象,这是一个聚合或者组合的关系。而且也是在Adapterrequest方法中调用了Adaptee对象中的方法,从这个角度而言,Adapter模式和Bridge模式是非常类似的。

但是,他们之间有本质的区别:

1. Adapter模式中,Adaptee本身往往已经是一个具体的、已经存在的类。在Bridge模式中,Implementor则是一个抽象类或者接口;

2. Adapter模式中,Adapter类也是一个具体的类。在Bridge模式中,Abstraction则是一个抽象类;

3. Adapter模式中,Adapter类派生于一个抽象类/接口(客户程序所期望的)。在Bridge模式中,Abstraction类则不存在这样的情况。

4. 最本质同时也是最重要的区别是,它们的意图是不同的。



posted on 2013-03-07 23:09 Jacc.Kim 阅读(278) 评论(0)  编辑 收藏 引用 所属分类: 设计模式

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理