C++設計模式-Bridge橋接模式

做用:將抽象部份與它的實現部份分離,使它們均可以獨立地變化。ios

將抽象(Abstraction)與實現(Implementation)分離,使得兩者能夠獨立地變化。編程

橋接模式號稱設計模式中最難理解的模式之一,關鍵就是這個抽象和實現的分離很是讓人奇怪,大部分人剛看到這個定義的時候都會認爲實現就是繼承自抽象,那怎麼可能將他們分離呢。設計模式

《大話設計模式》中就Bridge模式的解釋:函數

手機品牌和軟件是兩個概念,不一樣的軟件能夠在不一樣的手機上,不一樣的手機能夠有相同的軟件,二者都具備很大的變更性。若是咱們單獨以手機品牌或手機軟件爲基類來進行繼承擴展的話,無疑會使類的數目劇增而且耦合性很高,(若是更改品牌或增長軟件都會增長不少的變更)兩種方式的結構以下:ui

 

因此將二者抽象出來兩個基類分別是PhoneBrand和PhoneSoft,那麼在品牌類中聚合一個軟件對象的基類將解決軟件和手機擴展混亂的問題,這樣二者的擴展就相對靈活,剪短了二者的必要聯繫,結構圖以下:this

這樣擴展品牌和軟件就相對靈活獨立,達到解耦的目的!spa

 UML結構圖以下:設計

抽象基類及接口:指針

一、Abstraction::Operation():定義要實現的操做接口code

二、AbstractionImplement::Operation():實現抽象類Abstaction所定義操做的接口,由其具體派生類ConcreteImplemenA、ConcreteImplemenA或者其餘派生類實現。

三、在Abstraction::Operation()中根據不一樣的指針多態調用AbstractionImplement::Operation()函數。

理解:
Bridge用於將表示和實現解耦,二者能夠獨立的變化.在Abstraction類中維護一個AbstractionImplement類指針,須要採用不一樣的實現方式的時候只須要傳入不一樣的AbstractionImplement派生類就能夠了.

Bridge的實現方式其實和Builde十分的相近,能夠這麼說:本質上是同樣的,只是封裝的東西不同罷了.二者的實現都有以下的共同點:

抽象出來一個基類,這個基類裏面定義了共有的一些行爲,造成接口函數(對接口編程而不是對實現編程),這個接口函數在Buildier中是BuildePart函數在Bridge中是Operation函數;

其次,聚合一個基類的指針,如Builder模式中Director類聚合了一個Builder基類的指針,而Brige模式中Abstraction類聚合了一個AbstractionImplement基類的指針(優先採用聚合而不是繼承);

而在使用的時候,都把對這個類的使用封裝在一個函數中,在Bridge中是封裝在Director::Construct函數中,由於裝配不一樣部分的過程是一致的,而在Bridge模式中則是封裝在Abstraction::Operation函數中,在這個函數中調用對應的AbstractionImplement::Operation函數.就兩個模式而言,Builder封裝了不一樣的生成組成部分的方式,而Bridge封裝了不一樣的實現方式.

橋接模式就將實現與抽象分離開來,使得RefinedAbstraction依賴於抽象的實現,這樣實現了依賴倒轉原則,而無論左邊的抽象如何變化,只要實現方法不變,右邊的具體實現就不須要修改,而右邊的具體實現方法發生變化,只要接口不變,左邊的抽象也不須要修改。

經常使用的場景
1.當一個對象有多個變化因素的時候,考慮依賴於抽象的實現,而不是具體的實現。如上面例子中手機品牌有2種變化因素,一個是品牌,一個是功能。

2.當多個變化因素在多個對象間共享時,考慮將這部分變化的部分抽象出來再聚合/合成進來,如上面例子中的通信錄和遊戲,實際上是能夠共享的。

3.當咱們考慮一個對象的多個變化因素能夠動態變化的時候,考慮使用橋接模式,如上面例子中的手機品牌是變化的,手機的功能也是變化的,因此將他們分離出來,獨立的變化。

優勢
1.將實現抽離出來,再實現抽象,使得對象的具體實現依賴於抽象,知足了依賴倒轉原則。

2.將能夠共享的變化部分,抽離出來,減小了代碼的重複信息。

3.對象的具體實現能夠更加靈活,能夠知足多個因素變化的要求。

缺點
1.客戶必須知道選擇哪種類型的實現。

 

設計中有超過一維的變化咱們就能夠用橋模式。若是隻有一維在變化,那麼咱們用繼承就能夠圓滿的解決問題。

 代碼以下:

Abstraction.h

 1 #ifndef _ABSTRACTION_H_
 2 #define _ABSTRACTION_H_
 3 
 4 class AbstractionImplement;
 5 
 6 class Abstraction
 7 {
 8 public:
 9     virtual void Operation()=0;//定義接口,表示該類所支持的操做
10     virtual ~Abstraction();
11 protected:
12     Abstraction();
13 };
14 
15 class RefinedAbstractionA:public Abstraction
16 {
17 public:
18     RefinedAbstractionA(AbstractionImplement* imp);//構造函數
19     virtual void Operation();//實現接口
20     virtual ~RefinedAbstractionA();//析構函數
21 private:
22     AbstractionImplement* _imp;//私有成員
23 };
24 
25 class RefinedAbstractionB:public Abstraction
26 {
27 public:
28     RefinedAbstractionB(AbstractionImplement* imp);//構造函數
29     virtual void Operation();//實現接口
30     virtual ~RefinedAbstractionB();//析構函數
31 private:
32     AbstractionImplement* _imp;//私有成員
33 };
34 #endif

Abstraction.cpp

 1 #include "Abstraction.h"
 2 #include "AbstractionImplement.h"
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 Abstraction::Abstraction()
 8 {}
 9 
10 Abstraction::~Abstraction()
11 {}
12 
13 RefinedAbstractionA::RefinedAbstractionA(AbstractionImplement* imp)
14 {
15     this->_imp = imp;
16 }
17 
18 RefinedAbstractionA::~RefinedAbstractionA()
19 {
20     delete this->_imp;
21     this->_imp = NULL;
22 }
23 
24 void RefinedAbstractionA::Operation()
25 {
26     cout << "RefinedAbstractionA::Operation" << endl;
27     this->_imp->Operation();
28 }
29 
30 RefinedAbstractionB::RefinedAbstractionB(AbstractionImplement* imp)
31 {
32     this->_imp = imp;
33 }
34 
35 RefinedAbstractionB::~RefinedAbstractionB()
36 {
37     delete this->_imp;
38     this->_imp = NULL;
39 }
40 
41 void RefinedAbstractionB::Operation()
42 {
43     cout << "RefinedAbstractionB::Operation" << endl;
44     this->_imp->Operation();
45 }

AbstractImplement.h

 1 #ifndef _ABSTRACTIONIMPLEMENT_H_
 2 #define _ABSTRACTIONIMPLEMENT_H_
 3 
 4 //抽象基類,定義了實現的接口
 5 class AbstractionImplement
 6 {
 7 public:
 8     virtual void Operation()=0;//定義操做接口
 9     virtual ~AbstractionImplement();
10 protected:
11     AbstractionImplement();
12 };
13 
14 // 繼承自AbstractionImplement,是AbstractionImplement的不一樣實現之一
15 class ConcreteAbstractionImplementA:public AbstractionImplement
16 {
17 public:
18     ConcreteAbstractionImplementA();
19     void Operation();//實現操做
20     ~ConcreteAbstractionImplementA();
21 protected:
22 };
23 
24 // 繼承自AbstractionImplement,是AbstractionImplement的不一樣實現之一
25 class ConcreteAbstractionImplementB:public AbstractionImplement
26 {
27 public:
28     ConcreteAbstractionImplementB();
29     void Operation();//實現操做
30     ~ConcreteAbstractionImplementB();
31 protected:
32 };
33 #endif

AbstractImplement.cpp

 1 #include "AbstractionImplement.h"
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 AbstractionImplement::AbstractionImplement()
 7 {}
 8 
 9 AbstractionImplement::~AbstractionImplement()
10 {}
11 
12 ConcreteAbstractionImplementA::ConcreteAbstractionImplementA()
13 {}
14 
15 ConcreteAbstractionImplementA::~ConcreteAbstractionImplementA()
16 {}
17 
18 void ConcreteAbstractionImplementA::Operation()
19 {
20     cout << "ConcreteAbstractionImplementA Operation" << endl;
21 }
22 
23 ConcreteAbstractionImplementB::ConcreteAbstractionImplementB()
24 {}
25 
26 ConcreteAbstractionImplementB::~ConcreteAbstractionImplementB()
27 {}
28 
29 void ConcreteAbstractionImplementB::Operation()
30 {
31     cout << "ConcreteAbstractionImplementB Operation" << endl;
32 }

main.cpp

 1 #include "Abstraction.h"
 2 #include "AbstractionImplement.h"
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     /* 將抽象部分與它的實現部分分離,使得它們能夠獨立地變化
10 
11     一、抽象Abstraction與實現AbstractionImplement分離;
12 
13     二、抽象部分Abstraction能夠變化,如new RefinedAbstractionA(imp)、new RefinedAbstractionB(imp2);
14 
15     三、實現部分AbstractionImplement也能夠變化,如new ConcreteAbstractionImplementA()、new ConcreteAbstractionImplementB();
16 
17     */
18 
19     AbstractionImplement* imp = new ConcreteAbstractionImplementA();        //實現部分ConcreteAbstractionImplementA
20     Abstraction* abs = new RefinedAbstractionA(imp);                        //抽象部分RefinedAbstractionA
21     abs->Operation();
22 
23     cout << "-----------------------------------------" << endl;
24 
25     AbstractionImplement* imp1 = new ConcreteAbstractionImplementB();        //實現部分ConcreteAbstractionImplementB
26     Abstraction* abs1 = new RefinedAbstractionA(imp1);                        //抽象部分RefinedAbstractionA
27     abs1->Operation();
28 
29     cout << "-----------------------------------------" << endl;
30 
31     AbstractionImplement* imp2 = new ConcreteAbstractionImplementA();        //實現部分ConcreteAbstractionImplementA
32     Abstraction* abs2 = new RefinedAbstractionB(imp2);                        //抽象部分RefinedAbstractionB
33     abs2->Operation();
34 
35     cout << "-----------------------------------------" << endl;
36 
37     AbstractionImplement* imp3 = new ConcreteAbstractionImplementB();        //實現部分ConcreteAbstractionImplementB
38     Abstraction* abs3 = new RefinedAbstractionB(imp3);                        //抽象部分RefinedAbstractionB
39     abs3->Operation();
40 
41     cout << endl;
42     return 0;
43 }

代碼說明:
Bridge模式將抽象和實現分別獨立實現,在代碼中就是Abstraction類和AbstractionImplement類。

使用組合(委託)的方式將抽象和實現完全地解耦,這樣的好處是抽象和實現能夠分別獨立地變化,系統的耦合性也獲得了很好的下降。
GoF的那句話中的「實現」該怎麼去理解:「實現」特別是和「抽象」放在一塊兒的時候咱們「默認」的理解是「實現」就是「抽象」的具體子類的實現,可是這裏GoF所謂的「實現」的含義不是指抽象基類的具體子類對抽象基類中虛函數(接口)的實現,是和繼承結合在一塊兒的。而這裏的「實現」的含義指的是怎麼去實現用戶的需求,而且指的是經過組合(委託)的方式實現的,所以這裏的實現不是指的繼承基類、實現基類接口,而是指的是經過對象組合實現用戶的需求。

實際上上面使用Bridge模式和使用帶來問題方式的解決方案的根本區別在因而經過繼承仍是經過組合的方式去實現一個功能需求。

備註:

因爲實現的方式有多種,橋接模式的核心就是把這些實現獨立出來,讓他們各自變化。

將抽象部分與它的實現部分分離:實現系統可能有多角度(維度)分類,每一種分類均可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減小它們之間的耦合。

在發現須要多角度去分類實現對象,而只用繼承會形成大量的類增長,不能知足開放-封閉原則時,就要考慮用Bridge橋接模式了。

合成/聚合複用原則:儘可能使用合成/聚合,精良不要使用類繼承。優先使用對象的合成/聚合將有助於保持每一個類被封裝,並被集中在單個任務上。這樣類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物。

相關文章
相關標籤/搜索