Bridge橋模式也屬于”的單一職責“模式中的典型模式,
問題描述:
我們繪制圖形時,圖形可以有不同形狀以及不同顏色,比如圓形可以是紅的,綠的,方形可以是紅的綠的,如果用代碼來描繪這些類,會有如下:
1 class Shape{ 2 }; 3 class Rectangle : public Shape{ 4 }; 5 class Circle : public Shape{ 6 }; 7 class Color{ 8 }; 9 class Red : public Color{ 10 }; 11 class Blue : public Color{ 12 }; 13 class RedRectangle : public Red{ 14 }; 15 class BlueRectangle : public Blue{ 16 };
每增加一種圖形或者顏色,新增的類就會成倍得增長,而且CRedRectangle繼承于顏色,似乎也不太合理,CRedRectangle和CRed之間不是一種is-a的關系,下面通過橋模式改善它?
定義
將抽象部分(業務功能)與實作部分(平臺實作)分離,使它們都可以獨立地變化, ——《設計模式》GoF
簡單的說就是抽象對外提供的介面,對外隱瞞實作部分,在抽象中參考實作部分,從而實作抽象對實作部分的呼叫,而抽象中參考的實作部分可以在今后的開發中,切換為別的實作部分,
動機
- 解決繼承帶來的問題
物件的繼承關系是在編譯時就定義好的,無法在運行時改變從父類繼承的實作,父類實作中的任何變化都必然會導致子類發生變化,比如上面的代碼,Red類是Color抽象類的具體實作,RedRectangle從Red類中繼承了紅色屬性,就和顏色的實作系結在了一起,RedRectangle的顏色實作就難以修改或擴展,通過橋接模式把依賴具體實作,提升為依賴抽象,來完成物件和變化因素之間的低耦合,提高系統的可維護性和擴展性,橋接模式的主要目的是將一個物件的變化與其它變化隔離開,讓彼此之間的耦合度最低, - 合成/聚合復用原則
聚合表示一種弱的‘擁有’關系,體現的是A物件可以包含B物件,但B物件不是A物件的一部分;合成則是一種強的‘擁有’關系,體現了嚴格的部分和整體的關系,部分和整體的生命周期一樣,
組合:通常使用普通成員變數 ,如果類自己處理物件分配/釋放,則可以使用指標成員 ,負責零件的創建/銷毀
聚合:通常使用指向或參考成員,部件在于聚合類范圍之外創建,不負責創建/銷毀零件
繪制矩形、圓形、橢圓、正方形,我們至少需要4個形狀類,但是如果繪制的圖形需要具有不同的顏色,如紅色、綠色、藍色等,此時至少有如下兩種設計方案:
方案一:為每一種形狀都提供一套顏色版本
方案二:根據實際需要對形狀和顏色進行組合
明顯方案二采用聚合的方式可以減少很多類的數量,
UML類圖

Abstraction類定義了抽象類的介面,并且維護一個指向Implementor實作類的指標;
RefineAbstraction類擴充了Abstraction類的介面;
Implementor類定義了實作類的介面,這個介面不一定要與Abstraction的介面完全一致;實際上,這兩個介面可以完全不同;
ConcreteImplementor類實作了Implementor定義的介面,
代碼實作
1 #include <iostream> 2 3 using namespace std; 4 5 //具體實作的抽象 6 class Implementor { 7 public: 8 virtual void operatonImpl() = 0; 9 }; 10 11 //具體實作 12 class ConcreteImplementor : public Implementor { 13 public: 14 void oerationImpl() { cout << "OperationImpl" << endl; } 15 }; 16 17 class Abstruction { 18 public: 19 Abstruction(Implementor* pImpl) : m_pImpl(pImpl) {} 20 virtual void operation() = 0; 21 22 protected: 23 Implementor* m_pImpl; 24 }; 25 26 //重新定義抽象 27 class RedfinedAbstraction : public Abstruction { 28 public: 29 RedfineAbstraction(Implementor* pImpl) : Abstruction(pImpl) {} 30 void operation() { m_pImpl->operatonImpl(); } 31 }; 32 33 int main() { 34 Implementor* pImplObj = new ConcreteImplementor(); 35 Abstruction* pAbsObj = new RedfineAbstraction(pImplObj); 36 pAbsObj->operation(); 37 delete pImplObj; 38 pImplObj = nullptr; 39 delete pAbsObj; 40 pAbsObj = nullptr; 41 return 0; 42 }
使用橋模式重新實作形狀與顏色的代碼:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Color { 7 public: 8 virtual string name() = 0; 9 10 protected: 11 string mName; 12 }; 13 14 class Green : public Color { 15 public: 16 Green() { mName = "Green"; } 17 virtual ~Green() {} 18 virtual string name() { return mName; } 19 }; 20 21 class Red : public Color { 22 public: 23 Red() { mName = "Red"; } 24 virtual ~Red() {} 25 virtual string name() { return mName; } 26 }; 27 28 class Shape { 29 public: 30 Shape(Color* color) : mColor(color) {} 31 virtual void myShape() = 0; 32 33 protected: 34 Color* mColor; 35 }; 36 37 class Rectangle : public Shape { 38 public: 39 Rectangle(Color* color) : Shape(color) {} 40 virtual void myShape() { 41 cout << "Rectangle has a " << mColor->name() << " color\n"; 42 } 43 }; 44 45 class Circle : public Shape { 46 public: 47 Circle(Color* color) : Shape(color) {} 48 virtual void myShape() { 49 cout << "Circle has a " << mColor->name() << " color\n"; 50 } 51 }; 52 53 int main() { 54 Color* red = new Red(); 55 Color* green = new Green(); 56 57 Shape* rectangle = new Rectangle(red); 58 rectangle->myShape(); 59 Shape* circle = new Circle(green); 60 circle->myShape(); 61 62 return 0; 63 }
橋模式的優點
分離抽象介面及其實作的部分
- 橋接模式有點類似于多繼承,但是多繼承違背了類的單一職責原則(一個類只有一個變化的原因),復用性差,且多繼承結構中類的個數龐大,橋接模式是比多繼承方案更好的解決方案,
- 橋接模式提高了系統的可擴充性,在兩個變化維度中任意擴展一個維度,都不需要修改原系統,
- 實作細節對客戶透明,可以對用戶隱藏實作細節,
橋模式的缺點
- 橋接模式的引入會增加系統的理解與設計難度,由于聚合關聯關系建立在抽象層,要求開發者針對抽象進行設計與編程,
- 橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用范圍有局限性,
參考:
橋接模式(c++實作)
C++設計模式——橋接模式
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/341667.html
標籤:C++
