設計模式 - Bridge 橋模式


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++設計模式——橋接模式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM