橋接模式
模式定義
橋接模式(Bridge),將抽象部分與它的實現部分分離,使他們均可以獨立的變化。什麼叫抽象與他的實現分離,這並非說讓抽象類與其派生類分離,由於這沒有任何意義。實現指的是抽象類和它的派生類用來實現本身的對象。c++
模式動機
-
解決繼承帶來的問題編程
對象的繼承關係是在編譯時就定義好的,因此沒法再運行時改變從父類繼承的實現。子類的實現與他的父類有很是緊密的依賴關係,以致於父類實現中的任何變化必然會致使子類發生變化。當你須要複用子類時,若是繼承下來的實現不適合解決新的問題,則父類必須重寫或被其餘更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。設計模式
-
合成/聚合複用原則(CARP)spa
合成(組合)和聚合都是關聯的特殊種類。聚合表示一種弱的‘擁有’關係,體現的是A對象能夠包含B對象,但B對象不是A對象的一部分;合成則是一種強的‘擁有’關係,體現了嚴格的部分和總體的關係,部分和總體的生命週期同樣。聚合關係在繼承關係不適用的狀況下能夠作替代。其實只要真正深刻的理解了設計原則,不少設計模式其實就是原則的應用而已,或許在不知不覺中就在使用設計模式了。設計
-
設想若是要繪製矩形、圓形、橢圓、正方形,咱們至少須要4個形狀類,可是若是繪製的圖形須要具備不一樣的顏色,如紅色、綠色、藍色等,此時至少有以下兩種設計方案:code
-
第一種設計方案是爲每一種形狀都提供一套各類顏色的版本。對象
-
第二種設計方案是根據實際須要對形狀和顏色進行組合。blog
明顯方案二採用聚合的方式組織類結構可以使類的數量減小不少。固然這只是一個簡單的例子。繼承
-
UML類圖
源碼實現
-
color.h接口
#ifndef COLOR_H #define COLOR_H #include <QString> class Color { public: Color(){} virtual ~Color(){} virtual QString Name() = 0; protected: QString m_Name; }; class Black : public Color { public: Black(); virtual ~Black(); virtual QString Name(); }; class Red : public Color { public: Red(); virtual ~Red(); virtual QString Name(); }; #endif // COLOR_H
-
color.cpp
#include <QDebug> #include "color.h" Black::Black() { m_Name = "Black"; } Black::~Black() { } QString Black::Name() { return m_Name; } Red::Red() { m_Name = "Red"; } Red::~Red() { } QString Red::Name() { return m_Name; }
-
shape.h
#ifndef SHAPE_H #define SHAPE_H #include "color.h" //抽象類 class Shape { public: Shape(){} virtual ~Shape(){} void SetColor(Color* color); virtual void MyShape() = 0; protected: Color* m_Color; }; class Rectangle : public Shape { public: Rectangle(); ~Rectangle(); virtual void MyShape(); }; class Circle : public Shape { public: Circle(); ~Circle(); virtual void MyShape(); }; #endif // SHAPE_H
-
shape.cpp
#include <QDebug> #include "shape.h" void Shape::SetColor(Color *color) { m_Color = color; } Rectangle::Rectangle() { } Rectangle::~Rectangle() { } void Rectangle::MyShape() { qDebug() << "Rectangle" + QString(" And ") + m_Color->Name(); } Circle::Circle() { } Circle::~Circle() { } void Circle::MyShape() { qDebug() << "Circle" + QString(" And ") + m_Color->Name(); }
-
main.cpp
#include <QCoreApplication> #include "shape.h" #include "color.h" #define DELETEOBJECT(x) if(x != nullptr){delete x; x = nullptr;} int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Color* red = new Red(); Color* black = new Black(); //組合一個黑色的圓和一個紅色的方形 Shape* rectangle = new Rectangle(); rectangle->SetColor(red); Shape* circle = new Circle(); circle->SetColor(black); rectangle->MyShape(); circle->MyShape(); DELETEOBJECT(red); DELETEOBJECT(black); DELETEOBJECT(rectangle); DELETEOBJECT(circle); return a.exec(); }
-
運行結果
"Rectangle And Red"
"Circle And Black"
優勢
分離抽象接口及其實現部分。
-
橋接模式有時相似於多繼承方案,可是多繼承方案違背了類的單一職責原則(即一個類只有一個變化的緣由),複用性比較差,並且多繼承結構中類的個數很是龐大,橋接模式是比多繼承方案更好的解決方法。
-
橋接模式提升了系統的可擴充性,在兩個變化維度中任意擴展一個維度,都不須要修改原有系統。
-
實現細節對客戶透明,能夠對用戶隱藏實現細節。
缺點
-
橋接模式的引入會增長系統的理解與設計難度,因爲聚合關聯關係創建在抽象層,要求開發者針對抽象進行設計與編程。
-
橋接模式要求正確識別出系統中兩個獨立變化的維度,所以其使用範圍具備必定的侷限性。
總結
- 橋接模式將抽象部分與它的實現部分分離,使它們均可以獨立地變化。它是一種對象結構型模式,又稱爲柄體(Handle and Body)模式或接口(Interface)模式。
- 橋接模式包含以下四個角色:抽象類中定義了一個實現類接口類型的對象並能夠維護該對象;擴充抽象類擴充由抽象類定義的接口,它實現了在抽象類中定義的抽象業務方法,在擴充抽象類中能夠調用在實現類接口中定義的業務方法;實現類接口定義了實現類的接口,實現類接口僅提供基本操做,而抽象類定義的接口可能會作更多更復雜的操做;具體實現類實現了實現類接口而且具體實現它,在不一樣的具體實現類中提供基本操做的不一樣實現,在程序運行時,具體實現類對象將替換其父類對象,提供給客戶端具體的業務操做方法。
- 在橋接模式中,抽象化(Abstraction)與實現化(Implementation)脫耦,它們能夠沿着各自的維度獨立變化。
- 橋接模式的主要優勢是分離抽象接口及其實現部分,是比多繼承方案更好的解決方法,橋接模式還提升了系統的可擴充性,在兩個變化維度中任意擴展一個維度,都不須要修改原有系統,實現細節對客戶透明,能夠對用戶隱藏實現細節;其主要缺點是增長系統的理解與設計難度,且識別出系統中兩個獨立變化的維度並非一件容易的事情。
- 橋接模式適用狀況包括:須要在構件的抽象化角色和具體化角色之間增長更多的靈活性,避免在兩個層次之間創建靜態的繼承聯繫;抽象化角色和實現化角色能夠以繼承的方式獨立擴展而互不影響;一個類存在兩個獨立變化的維度,且這兩個維度都須要進行擴展;設計要求須要獨立管理抽象化角色和具體化角色;不但願使用繼承或由於多層次繼承致使系統類的個數急劇增長的系統。