橋接模式將抽象(Abstraction)與實現(Implementation)分離,使得兩者能夠獨立地變化。ios
橋接模式將抽象和實現分別獨立實現,即Abstraction類和Implement類。編程
橋接模式中的實現不是指抽象基類的具體子類對抽象基類中虛函數(接口)的實現,是指怎麼去實現用戶的需求,即在Implement具體類中實現Abstraction的接口功能,而且是經過組合(委託)的方式實現的,所以橋接模式中實現不是指的繼承基類、實現基類接口,而是指的是經過對象組合實現用戶的需求。設計模式
橋接模式將繼承關係轉換爲組合關係,從而下降了系統間的耦合,減小了代碼編寫量。使用組合(委託)的方式將抽象和實現完全地解耦,好處是抽象和實現能夠分別獨立地變化,系統的耦合性也獲得了很好的下降。app
將抽象部分與它的實現部分分離,使得它們能夠獨立地變化。抽象Abstraction與實現Implement分離,抽象部分Abstraction能夠變化,如new RefinedAbstractionA(imp)、new RefinedAbstractionB(imp);實現部分Implement也能夠獨立變化,如new ConcreteImplementA()、new ConcreteImplementB()。ide
抽象類(Abstraction):定義抽象類接口而且維護一個指向Implement的指針函數
擴充抽象類(RefinedAbstraction):擴充由Abstraction定義的接口ui
實現類接口(Implement):定義實現類的接口,該接口不必定要與 Abstraction的接口徹底一致;事實上這兩個接口能夠徹底不一樣。通常來說, Implement接口僅提供基本操做,而 Abstraction則定義了基於這些基本操做的較高層次的操做。spa
具體實現類(ConcreteImplement):實現Implement接口並定義具體實現。操作系統
Abstraction::request():定義要實現的操做接口,在Abstraction::request()中根據不一樣的指針多態調用Implement::operation()函數。.net
Implement::operation():實現抽象類Abstaction所定義操做的接口,由其具體派生類ConcreteImplemenA、ConcreteImplemenB或者其餘派生類實現。
優勢:
A、分離接口及其實現部分 。一個實現未必不變地綁定在一個接口上。抽象類的實現能夠在運行時刻進行配置,一個對象甚至能夠在運行時刻改變它的實現。將Abstraction與Implement分離有助於下降對實現部分編譯時刻的依賴性,當改變一個實現類時,並不須要從新編譯Abstraction類和它的客戶程序。爲了保證一個類庫的不一樣版本之間的二進制兼容性,必定要有這個性質。另外,接口與實現分離有助於分層,從而產生更好的結構化系統,系統的高層部分僅需知道Abstraction和Implement便可。
B、提升可擴充性 。能夠獨立地對Abstraction和Implement層次結構進行擴充。
C、實現細節對客戶透明 。能夠對客戶隱藏實現細節,例如共享Implement對象以及相應的引用計數機制。
D、將能夠共享的變化部分,抽離出來,減小了代碼的重複信息。
E、對象的具體實現能夠更加靈活,能夠知足多個因素變化的要求。
缺點:
A、橋接模式的引入會增長系統的理解與設計難度,因爲聚合關聯關係創建在抽象層,要求開發者針對抽象進行設計與編程。
B、橋接模式要求正確識別出系統中兩個獨立變化的維度,所以其使用範圍具備必定的侷限性。
C、客戶必須知道選擇哪種類型的實現。
橋接模式使用場景:
A、當一個對象有多個變化因素的時候,考慮依賴於抽象的實現,而不是具體的實現。如手機品牌有2種變化因素,一個是品牌,一個是功能。
B、當多個變化因素在多個對象間共享時,考慮將變化的部分抽象出來再聚合或組合進來。
C、當考慮一個對象的多個變化因素能夠動態變化的時候,考慮使用橋接模式,如手機的手機品牌是變化的,手機的功能也是變化的,因此將每一個可變化的因數分離出來,獨立的變化。
抽象工廠模式能夠用來建立和配置一個特定的橋接模式。
適配器模式用來幫助無關的類協同工做,一般在系統設計完成後纔會被使用。然而,橋接模式則是在系統開始時就被使用,使得抽象接口和實現部分能夠獨立進行改變。
橋接模式和裝飾模式在必定程度上都是爲了減小子類的數目,避免出現複雜的繼承關係,但解決的方法卻各有不一樣。裝飾模式把子類中比基類中多出來的部分放到單獨的類裏面,以適應新功能增長的須要,當把描述新功能的類封裝到基類的對象裏面時,就獲得所須要的子類對象,描述新功能的類經過組合能夠實現不少的功能組合。 橋接模式則把原來的基類的實現化細節抽象出來,在構造到一個實現化的結構中,而後再把原來的基類改形成一個抽象化的等級結構,就能夠實現系統在多個維度上的獨立變化 。
Abstraction基類:
#ifndef ABSTRACTION_H #define ABSTRACTION_H #include "Implement.h" //抽象基類 class Abstraction { public: //須要實現的接口 virtual void request() = 0; protected: Abstraction(Implement* imp):m_implement(imp){} protected: Implement* m_implement; }; #endif // ABSTRACTION_H
RefinedAbstractionA具體類:
#ifndef REFINEDABSTRACTIONA_H #define REFINEDABSTRACTIONA_H #include "Abstraction.h" #include <iostream> #include "Implement.h" using namespace std; class RefinedAbstractionA : public Abstraction { public: RefinedAbstractionA(Implement* imp):Abstraction(imp){} virtual void request() { cout << "RefinedAbstractionA::request" << endl; //調用實現部分 m_implement->operation(); } }; #endif // REFINEDABSTRACTIONA_H
RefinedAbstractionB具體類:
#ifndef REFINEDABSTRACTIONB_H #define REFINEDABSTRACTIONB_H #include "Abstraction.h" #include <iostream> #include "Implement.h" using namespace std; class RefinedAbstractionB : public Abstraction { public: RefinedAbstractionB(Implement* imp):Abstraction(imp){} virtual void request() { cout << "RefinedAbstractionB::request" << endl; //調用實現部分 m_implement->operation(); } }; #endif // REFINEDABSTRACTIONB_H
Implement抽象實現類:
#ifndef IMPLEMENT_H #define IMPLEMENT_H //抽象實現類 class Implement { public: virtual void operation() = 0; protected: Implement(){} }; #endif // IMPLEMENT_H
ConcreteImplementA具體實現類:
#ifndef CONCRETEIMPLEMENTA_H #define CONCRETEIMPLEMENTA_H #include "Implement.h" #include <iostream> using namespace std; //具體實現類 class ConcreteImplementA : public Implement { public: //具體實現的功能函數 void operation() { cout << "ConcreteImplementA::operation()" << endl; } }; #endif // CONCRETEIMPLEMENTA_H
ConcreteImplementB具體實現類:
#ifndef CONCRETEIMPLEMENTB_H #define CONCRETEIMPLEMENTB_H #include "Implement.h" #include <iostream> using namespace std; //具體實現類 class ConcreteImplementB : public Implement { public: //具體實現的功能函數 void operation() { cout << "ConcreteImplementB::operation()" << endl; } }; #endif // CONCRETEIMPLEMENTB_H
客戶調用程序:
#include "Abstraction.h" #include "Implement.h" #include "ConcreteImplementA.h" #include "ConcreteImplementB.h" #include "RefinedAbstractionA.h" #include "RefinedAbstractionB.h" int main() { Implement* imp = new ConcreteImplementA(); Abstraction* abs = new RefinedAbstractionA(imp); abs->request(); Implement* imp1 = new ConcreteImplementB(); Abstraction* abs1 = new RefinedAbstractionB(imp1); abs1->request(); return 0; }
將抽象部分與實現部分分離:實現系統可能有多角度(維度)分類,每一種分類均可能變化,把多種角度分離出來讓它們獨立變化,減小它們之間的耦合。
在發現須要多角度去分類實現對象,而只用繼承會形成大量的類增長,不能知足開放-封閉原則時,要考慮用橋接模式。
組合/聚合複用原則:儘可能使用組合/聚合,不要使用類繼承。
優先使用對象的組合/聚合將有助於保持每一個類被封裝,並被集中在單個任務上。類和類繼承層次會保持較小規模,而且不太可能增加爲不可控制的龐然大物。
電腦品牌和操做系統是兩個概念,不一樣的品牌的電腦能夠安裝相同或不一樣的操做系統,二者都具備很大的變更性。若是單獨以電腦品牌或操做系統爲基類來進行繼承擴展的話,會使類的數目劇增而且耦合性很高,若是更改電腦品牌或增長操做系統類型都會增長不少的變更。
將二者抽象出來兩個基類分別是Computer和OS,在Computer類中聚合一個OS對象的基類將解決電腦品牌和操做系統擴展混亂的問題,二者的擴展就相對靈活,剪短了二者的必要聯繫。
Computer接口:
#ifndef COMPUTER_H #define COMPUTER_H class OS; class Computer { public: virtual void installOS(OS* os) = 0; }; #endif // COMPUTER_H
AppleComputer具體實現:
#ifndef APPLECOMPUTER_H #define APPLECOMPUTER_H #include "Computer.h" #include "OS.h" class AppleComputer : public Computer { public: virtual void installOS(OS* os) { cout << "AppleComputer "; os->installOS_Imp(); } }; #endif // APPLECOMPUTER_H
ThinkPadComputer具體實現:
#ifndef THINKPADCOMPUTER_H #define THINKPADCOMPUTER_H #include "Computer.h" #include "OS.h" class ThinkPadComputer : public Computer { public: virtual void installOS(OS* os) { cout << "ThinkPadComputer "; os->installOS_Imp(); } }; #endif // THINKPADCOMPUTER_H
OS接口:
#ifndef OS_H #define OS_H #include <iostream> using namespace std; class OS { public: virtual void installOS_Imp() = 0; }; #endif // OS_H
LinuxOS具體實現:
#ifndef LINUXOS_H #define LINUXOS_H #include "OS.h" class LinuxOS : public OS { public: virtual void installOS_Imp() { cout << "has installed Linux OS" << endl; } }; #endif // LINUXOS_H
WindowsOS具體實現:
#ifndef WINDOWSOS_H #define WINDOWSOS_H #include "OS.h" class WindowsOS : public OS { public: virtual void installOS_Imp() { cout << "has installed Windows OS" << endl; } }; #endif // WINDOWSOS_H
客戶調用程序:
#include "OS.h" #include "Computer.h" #include "LinuxOS.h" #include "WindowsOS.h" #include "AppleComputer.h" #include "ThinkPadComputer.h" int main() { OS* lin = new LinuxOS(); OS* win = new WindowsOS(); Computer* apple = new AppleComputer(); Computer* thinkpad = new ThinkPadComputer(); apple->installOS(lin); apple->installOS(win); thinkpad->installOS(win); thinkpad->installOS(lin); delete lin,win,apple,thinkpad; return 0; }