轉(zhuǎn)載:
http://patmusing.blog.163.com/blog/static/13583496020100231174397/
Bridge模式又稱為Handle/Body模式。
在軟件系統(tǒng)中,經(jīng)常面臨著“某些結(jié)構(gòu)復(fù)雜的對(duì)象”的創(chuàng)建工作,由于需求的變化,這些對(duì)象經(jīng)常面臨著劇烈的變化,但是他們卻擁有比較穩(wěn)定一致的接口。大部分創(chuàng)建型模式,就是為了解決如何向“客戶程序”隔離出“這些易變對(duì)象”,從而使得“依賴這些易變對(duì)象的客戶程序”不隨著需求的改變而改變。
事實(shí)上,上面的假設(shè)是經(jīng)常面臨劇烈變化的對(duì)象(實(shí)現(xiàn)細(xì)節(jié)b)擁有比較穩(wěn)定一致的接口(抽象B)。現(xiàn)在的問(wèn)題是,如果抽象B由于一些固有的原因也是面臨著劇烈變化,那應(yīng)該怎么辦?
業(yè)務(wù)舉例:
假如我們需要開(kāi)發(fā)一個(gè)同時(shí)支持PC和手機(jī)的坦克游戲,游戲在PC和手機(jī)上的功能都一樣,都有同樣的類型,面臨同樣的功能需求變化,坦克有不同的型號(hào):T50、T75和T90。(上面所言的抽象B就是坦克,現(xiàn)在抽象B即坦克本身也要變化了,需要PC上的坦克和手機(jī)上的坦克)
對(duì)于其中的坦克設(shè)計(jì),我們可能很容易設(shè)計(jì)出來(lái)一個(gè)Tank的抽象基類,然后各種不同型號(hào)的Tank繼承該基類:
// 抽象的坦克
class Tank
{
public:
virtual void shot() = 0; // 射擊
virtual void run() = 0; // 行進(jìn)
virtual void turn() = 0; // 轉(zhuǎn)向
};
// 不同型號(hào)的坦克
class T50 : public Tank
{
...
};
class T75 : public Tank
{
...
};
class T90 : public Tank
{
...
};
由于PC機(jī)上和手機(jī)的圖形繪制、聲效、操作等具體實(shí)現(xiàn)有很大的差別,因此,對(duì)于各種型號(hào)的坦克,都要提供各種不同平臺(tái)上的實(shí)現(xiàn):
// PC機(jī)上的各型號(hào)坦克的實(shí)現(xiàn)
class PCT50 : public T50
{
...
};
class PCT75 : public T75
{
...
};
class PCT90 : public T90
{
...
};
// 手機(jī)上的各型號(hào)坦克的實(shí)現(xiàn)
class MobileT50 : public T50
{
...
};
class MobileT75 : public T75
{
...
};
class MobileT90 : public T90
{
...
};
這樣以來(lái)就有會(huì)產(chǎn)生如上6個(gè)leaf或者terminal 類。
上面的設(shè)計(jì)思路會(huì)帶來(lái)很多問(wèn)題:有很多重復(fù)的代碼,類的結(jié)果過(guò)于復(fù)雜,難以維護(hù),以至于引入任何新的平臺(tái),比如TV上的Tank游戲,就會(huì)產(chǎn)生9個(gè)leaf或terminal類,顯然會(huì)讓整個(gè)類層級(jí)結(jié)構(gòu)劇烈復(fù)雜化起來(lái)。
上述問(wèn)題的結(jié)癥:Tank類具有兩個(gè)變化的維度,即“型號(hào)的變化”和“平臺(tái)的變化”,Bridge設(shè)計(jì)模式就是利用面向?qū)ο蟮募夹g(shù)來(lái)使得Tank類型可以輕松地沿著“型號(hào)”和“平臺(tái)”兩個(gè)方向變化,而不引入額外的復(fù)雜度。
“Decouple an abstraction from its implementation so that the two can vary independently.” – GoF
下面是Bridge設(shè)計(jì)模式的類圖:
另外一個(gè)被廣泛用來(lái)說(shuō)明Bridge設(shè)計(jì)模式的例子,就是GoF原著《Design Patterns, Elements of Reusable Object-Oriented Software》中講到的在不同的圖形系統(tǒng)下繪圖的情況。
下面是C++實(shí)現(xiàn)代碼示例:
// 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相同,因?yàn)槿绻嗤?span style="font-family: 宋體; color: green; font-size: 9pt; mso-ascii-font-family: Arial; mso-hansi-font-family: 'Courier New'; mso-bidi-font-family: Arial; mso-font-kerning: 0pt; mso-no-proof: yes">那么pli = plim;就必須寫(xiě)成:
{ // this->pli = pli;
pli = plim; // 而這會(huì)導(dǎo)致pli不知所指,這或許算是VS2005的一個(gè)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"; // 假定在這里畫(huà)坦克
}
string move_tank()
{
return "PC platform: Move a tank"; // 假定在這里移動(dòng)坦克
}
string do_shot()
{
return "PC platform: Fire the target"; // 假定在這里坦克開(kāi)火
}
string turn()
{
return "PC platform: Turn direction"; // 假定在這里坦克轉(zhuǎn)彎
}
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;
}
};
// 測(cè)試代碼: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到此已經(jīng)無(wú)所指向,詳見(jiàn)Tank類的構(gòu)造函數(shù)
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到此已經(jīng)無(wú)所指向,詳見(jiàn)Tank類的構(gòu)造函數(shù)
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到此已經(jīng)無(wú)所指向,詳見(jiàn)Tank類的構(gòu)造函數(shù)
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到此已經(jīng)無(wú)所指向
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到此已經(jīng)無(wú)所指向
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到此已經(jīng)無(wú)所指向,詳見(jiàn)Tank類的構(gòu)造函數(shù)
delete mo_T90;
return 0;
}
運(yùn)行結(jié)果:
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...
上述實(shí)現(xiàn)代碼中各個(gè)類和Bridge模式中的各個(gè)類之間的對(duì)應(yīng)關(guān)系:
Tank < ------ > Abstraction
T50、T75和T90 < ------ > RefinedAbstraction
PlatformImplementor < ------ > Implementor
PCPlatformImplementor < ------ > ConcreteImplementorA
MobilePlatformImplementor < ------ > ConcreteImplementorB
前面講到的Adapter模式(對(duì)象適配器形式),從UML的角度來(lái)看,也可以畫(huà)成:

因?yàn)?/span>Adapter中包含了一個(gè)Adaptee對(duì)象,這是一個(gè)聚合或者組合的關(guān)系。而且也是在Adapter的request方法中調(diào)用了Adaptee對(duì)象中的方法,從這個(gè)角度而言,Adapter模式和Bridge模式是非常類似的。
但是,他們之間有本質(zhì)的區(qū)別:
1. 在Adapter模式中,Adaptee本身往往已經(jīng)是一個(gè)具體的、已經(jīng)存在的類。在Bridge模式中,Implementor則是一個(gè)抽象類或者接口;
2. 在Adapter模式中,Adapter類也是一個(gè)具體的類。在Bridge模式中,Abstraction則是一個(gè)抽象類;
3. 在Adapter模式中,Adapter類派生于一個(gè)抽象類/接口(客戶程序所期望的)。在Bridge模式中,Abstraction類則不存在這樣的情況。
4. 最本質(zhì)同時(shí)也是最重要的區(qū)別是,它們的意圖是不同的。