一、概念
將抽象部分(業務功能)與實現部分(平臺實現)分離,使它們都可以獨立地變化。 ——《設計模式》GoF
二、動機
由於某些類型的固有的實現邏輯,使得它們具有兩個變化的維度,乃至多個維度的變化。
如何應對這種“多維度的變化”?如何利用面向對象技術來使得類型可以輕鬆地沿着兩個乃至多個方向變化,而不引入額外的複雜度?
三、源代碼講解
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平臺實現PC,Mobile,主要不同是在平臺實現上,播放聲音,圖片繪製,端口寫入數據,連接網絡上不同。下面的不同註釋方式代表不同的實現
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//業務抽象:在每一種的平臺上,我們還要實現不同的功能,比如:經典版,完美版
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect(); //調用的基類方法
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
//功能變多
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//編譯時裝配
Messager *m = new MobileMessagerPerfect();
}
四、使用橋模式進行改進
// 把業務功能抽象出來
class Messager {
protected:
// 使用組合而非繼承
MessagerImp* messagerImp;
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager() { }
};
// 平臺實現與業務功能是不同的變化方向
class MessagerImp {
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~MessagerImp() { }
};
// 平臺實現
class PCMessagerImp : public MessagerImp {
public:
virtual void PlaySound() {
//**********
}
virtual void DrawShape() {
//**********
}
virtual void WriteText() {
//**********
}
virtual void Connect() {
// **********
}
};
class MobileMessagerImp : public MessagerImp {
public:
virtual void PlaySound() {
// ==========
}
virtual void DrawShape() {
// ==========
}
virtual void WriteText() {
// ==========
}
virtual void Connect() {
// ==========
}
};
// 抽象業務
class MessagerLite : public Messager {
// 繼承轉組合
MessagerImp* messager; // 在未來是MobileMessagerBase,和PcMessageBase
public:
virtual void Login(string username, string password) {
messager->Connect();
// ........
}
virtual void SendMessage(string message) {
messager->WriteText();
// ........
}
virtual void SendPicture(Image image) {
messager->DrawShape();
// ........
}
};
class MessagerPerfect : public Messager {
MessagerImp* messager; // 在未來是MobileMessagerBase,和PcMessageBase
public:
virtual void Login(string username, string password) {
messager->PlaySound();
// ********
messager->Connect();
// ........
}
virtual void SendMessage(string message) {
messager->PlaySound();
// ********
messager->WriteText();
// ........
}
virtual void SendPicture(Image image) {
messager->PlaySound();
// ********
messager->DrawShape();
// ........
}
};
void Process() {
// 運行時裝配
MessagerImp *mImp = new PCMessagerImp();
Messager *m = new Messager(mImp);
}
五、類圖結構
注意:穩定區域有一個多態指針在Messager中指向MessagerImp,這是和Decorator模式的一個區別。將抽象部分(業務功能)與實現部分(平臺實現)分離,使它們都可以獨立地變化。
六、要點總結
-
Bridge模式使用“對象間的組合關係”解耦了抽象和實現之間固 有的綁定關係,使得抽象和實現可以沿着各自的維度來變化。所謂 抽象和實現沿着各自緯度的變化,即“子類化”它們。
-
Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背單一職責原則(即一個類只有一個變化的原因),複用性比較差。 Bridge模式是比多繼承方案更好的解決方法。
-
Bridge模式的應用一般在“兩個非常強的變化維度”,有時一個類也有多於兩個的變化維度,這時可以使用Bridge的擴展模式。