設計模式(五)橋接模式(轉)

原文地址:http://www.jellythink.com/archives/132ios

C++設計模式——橋接模式

問題描述

如今要去畫一個圖形,圖形有長方形、圓形和扇形等等;而圖形又能夠加上不一樣的顏色,而後,咱們就能夠畫出紅色的長方形,綠色的長方形;紅色的圓形,綠色的圓形等等。而這種圖形的形狀在變化,圖形的顏色也在變化,當使用代碼去實現時,如何面對這種多方面的變化呢?這就要說到今天的橋接模式了。設計模式

什麼是橋接模式?

對於上述的圖形與顏色的問題時,不少時候,咱們讓各個圖形類繼承顏色類,好比:ide

 1 class CShape
 2 {
 3 };
 4 class CRectangle : public CShape
 5 {
 6 };
 7 class CCircle : public CShape
 8 {
 9 };
10 class CColor
11 {
12 };
13 class CRed : public CColor
14 {
15 };
16 class CBlue : public CColor
17 {
18 };
19 class CRedRectangle : public CRed
20 {
21 };
22 class CBlueRectangle : public CBlue
23 {
24 };

每當咱們增長一個新的圖形,或者增長一種新的顏色時,對應的類就會以相乘的速度進行增長。當系統中的類變的多時,對應的管理也就變的複雜,這不是咱們但願看到的。同時,咱們能夠看到CRedRectangle類繼承自CRed類,這種繼承關係合理嗎?且不說有的系統是如此實現的,紅色的矩形是紅色嗎?很顯然,CRedRectangle和CRed之間不是一種is-a的關係,因此,上面的實現是及其不合理的。那麼它們是什麼關係呢?接着往下看。網站

在GOF的《設計模式:可複用面向對象軟件的基礎》一書中對橋接模式是這樣說的:將抽象部分和它的實現部分分離,使它們均可以獨立的變化。簡單粗暴的說,就是抽象對外提供調用的接口;對外隱瞞實現部分,在抽象中引用實現部分,從而實現抽象對實現部分的調用,而抽象中引用的實現部分能夠在從此的開發過程當中,切換成別的實現部分。spa

爲何要使用橋接模式?

當一個抽象可能有多個實現時,一般用繼承來協調它們。抽象類定義對該抽象的接口,而具體的子類則用不一樣方式加以實現。可是此方法有時不夠靈活。繼承機制將抽象部分與它的實現部分固定在一塊兒,使得難以對抽象部分和實現部分獨立的進行修改、擴充和重用。橋接模式把依賴具體實現,提高爲依賴抽象,來完成對象和變化因素之間的低耦合,提升系統的可維護性和擴展性。橋接模式的主要目的是將一個對象的變化與其它變化隔離開,讓彼此之間的耦合度最低。設計

何時使用橋接模式?

  1. 若是不但願在抽象和它的實現部分之間有一個固定的綁定關係,也就是繼承關係;若是咱們打破了這種固定的綁定關係,之後,就能夠方便的在抽象部分切換不一樣的實現部分;
  2. 若是但願類的抽象以及它的實現都應該能夠經過生成子類的方法加以擴充;若是不使用橋接模式,使用繼承去實現時,在抽象類中添加一個方法,則在對應的實現類中也須要作對應的改動,這種實現不符合鬆耦合的要求;
  3. 若是要求對一個抽象的實現部分的修改對客戶不產生影響,即客戶的代碼不須要從新編譯,在後面的項目經驗會說這方面;
  4. 若是想對客戶徹底隱藏抽象的實現部分;
  5. 若是一個對象有多個變化因素的時候,經過抽象這些變化因素,將依賴具體實現,修改成依賴抽象;
  6. 若是某個變化因素在多個對象中共享時,能夠抽象出這個變化因素,而後實現這些不一樣的變化因素。

上面使用的場景,是一種建議,也是一種參考。在項目中要很好的把握一個設計模式,是有必定的難度的;當在實際項目中遇到知足上面的一點或者幾點時,能夠考慮使用橋接模式。指針

UML類圖

果凍想 | 一個原創文章分享網站

Abstraction類定義了抽象類的接口,而且維護一個指向Implementor實現類的指針;code

RefineAbstraction類擴充了Abstraction類的接口;orm

Implementor類定義了實現類的接口,這個接口不必定要與Abstraction的接口徹底一致;實際上,這兩個接口能夠徹底不一樣;對象

ConcreteImplementor類實現了Implementor定義的接口。

代碼實現

 1 /*
 2 ** FileName     : BridgePatternDemo
 3 ** Author       : Jelly Young
 4 ** Date         : 2013/12/4
 5 ** Description  : More information, please go to http://www.jellythink.com
 6 */
 7 #include <iostream>
 8 using namespace std;
 9 class Implementor
10 {
11 public:
12      virtual void OperationImpl() = 0;
13 };
14 class ConcreteImpementor : public Implementor
15 {
16 public:
17      void OperationImpl()
18      {
19           cout<<"OperationImpl"<<endl;
20      }
21 };
22 class Abstraction
23 {
24 public:
25      Abstraction(Implementor *pImpl) : m_pImpl(pImpl){}
26      virtual void Operation() = 0;
27 protected:
28      Implementor *m_pImpl;
29 };
30 class RedfinedAbstraction : public Abstraction
31 {
32 public:
33      RedfinedAbstraction(Implementor *pImpl) : Abstraction(pImpl){}
34      void Operation()
35      {
36           m_pImpl->OperationImpl();
37      }
38 };
39 int main(int argc, char *argv[])
40 {
41      Implementor *pImplObj = new ConcreteImpementor();
42      Abstraction *pAbsObj = new RedfinedAbstraction(pImplObj);
43      pAbsObj->Operation();
44      delete pImplObj;
45      pImplObj = NULL;
46      delete pAbsObj;
47      pAbsObj = NULL;
48      return 0;
49 }
View Code

根據對代碼的理解,能想象到CRedRectangle和CRed是什麼關係嗎?咱們能夠理解爲紅色的矩形包含紅色,也就是包含的關係,也就是軟件設計中的組合關係(has-a)。

項目經驗

這是一個我經歷的項目,也是作起來比較輕鬆的一個項目。項目是這樣的,須要對一箇中間的通訊庫進行改寫,保留之前的通訊方式的同時,須要使用一種新的通訊協議去和底層模塊進行通訊。現有的代碼是一個COM程序,向外提供了能夠調用的接口。根據客戶提供的源碼,咱們進行了分析;在分析以前,咱們有一種擔憂,就是怕用戶的代碼是接口和實現混在一塊兒的;可是,分析以後,讓咱們很吃驚,客戶的代碼結構很清晰,層次很是清楚,代碼中使用的就是咱們今天這裏說的橋接模式。因爲抽象的接口和實現徹底進行了分離,咱們在進行重寫時,只須要實現咱們的一個類,而後在接口中引用咱們實現的類,就大功告成了,這樣作到了客戶端不須要作任何修改,就能夠完美的替換掉原來的通訊層,真的是前人栽樹樹,後人乘涼啊。

總結

橋接模式使得抽象和實現進行了分離,抽象不用依賴於實現,讓抽象和實現部分各自修改起來都很方便,使用組合(就是Abstraction類中包含了Implementor)的方式,下降了耦合度,同時也有助於分層,從而產生更好的結構化系統。經過實際的項目經驗,使用了橋接模式的代碼,對之後的擴展有很大的幫助。

相關文章
相關標籤/搜索