2018-09-20 10:53:13ios
濫用繼承會帶來麻煩(實際上何止是麻煩,還會帶來性能上的額外開銷,關於繼承的問題,能夠查看繼承相關的文章)。好比,對象的繼承關係是在編譯時就定義好了,因此沒法在運行時改變從父類繼承的實現。子類實現與它的父類有很是緊密的依賴關係。以致於父類中的任何變化必然會致使子類發生變化。當你須要複用子類時,若是繼承下來的實現不適合解決新的問題,則父類必須重寫或被其它更適合的類替換。這種依賴關係限制了靈活性並最終限制了複用性。致使這種問題的緣由是繼承是一種強耦合的關係,是is -a 的關係。設計模式
優先使用對象合成、聚合,而不是類繼承。(想一下兩種模式的適配器,更推薦使用對象適配器就是這個原則的體現了)ide
合成(Composition,有時也叫組合)和聚合都是關聯的特殊種類。聚合表示一種弱的擁有關係,體現的是A對象能夠包含B對象,可是B對象不是A對象的一部分;合成則是一種強的擁有關係,體現了嚴格的總體和部分的關係,部分和總體的生命週期是同樣的。優先使用對象的聚合、合成將有助於你保持每一個類被封裝,並被集中在單個任務上,這樣類和類的繼承就會保持較小的規模,而且不太可能增加爲不可控制的龐然大物。性能
聚合和組合關係,這實際上是須要從宏觀上來理解的,而不能從微觀角度理解。組合必然是幾個組件,你們每一個都不能少,少了就不是一個總體,這是一個強擁有的關係。而聚合,多你一個很少,少你一個很多,就像《大話設計模式》裏講的大雁和雁羣的關係,大雁A、大雁B、大雁C、大雁D等無數多隻大雁聚合在一塊兒就是一個雁羣,但是你能說大雁A離開了雁羣這個雁羣就不是雁羣了嗎?顯然不能。可是在具體實現上,其實大都是以類的數據成員來實現的。最多就是在組合的狀況下class內嵌套class,可是這種作法並很差,由於過多的嵌套,可能會形成這個類的臃腫。編碼
橋接模式(Bridge),將抽象部分與它的實現部分分離,使它們均可以獨立地變化。這裏的抽象與它的實現分離,並非指讓抽象類和派生類分類,這沒有任何意義。實現指的是抽象類和它的派生類用來實現本身的對象。其實就是說,一個系統的實現,可能有多個角度的分類,每一種分類都有可能變化,那麼就把這種多角度分離出來讓它們獨自變化。舉例來講,手機便可以按照品牌分類(手機是抽象,功能是實現),也能夠按照功能分類(功能是實現,而手機變成了抽象)。spa
按照品牌分類實現類圖:設計
按照功能分類實現結構圖:3d
能夠看到上面兩種接口圖,模塊與模塊之間有着極強的耦合度,對按照手機品牌分類的結構中,當有新手機品牌加入的時候,你須要爲這一款手機從新開發功實現TaoBao、Game(我知道你會說軟件會兼容,可是這裏暫時不考慮這個,就假設沒有兼容性)。對按照功能來進行分類的時候,每增長一個新功能就要爲對應的品牌獨立開發相應的功能。指針
實現方式是多種多樣的,而橋接模式的核心意圖就是把實現獨立出來,讓它們各自獨立的變化,而且它們本身的變化不會影響到其它的實現,從而達到應對變化的目的。按照橋接的思路進行設計結構圖以下:code
優勢:
1.橋接分離了抽象和實現的具體聯繫,使得實現和抽象均可以去按照各自的維度去變化,並且相互之間不會產生影響。所謂隔離了抽象和實現,其實就是經過聚合的方式來實現了組件的動態添加和離開,子類不一樣形式的組合可以構建出不一樣的對象。
2.在設計上它能夠用來代替多層繼承方案。當繼承體系達到了必定深度以後,會致使大量的子類,以及冗餘的功能,而且子類自己的管理也是一個問題。
3.橋接模式提升了系統的可擴展性,由於抽象和實現,能夠按照各自不一樣的維度進行變化,進而組合出不一樣的類型
缺點:
1.增長了設計和理解難度,由於關聯關係從一開始就是創建在抽象層面的,意味着編碼工做要針對抽象層進行。
2.橋接模式要求系統正確的識別各個獨立變化的維度,可是識別這些維度也須要必定的考量。
橋接模式使用的關鍵是分清楚誰是實現,誰是抽象。假設咱們有一間很是大的圖書館,館藏豐富,內含n個區域,每一個區域中有不一樣種類的書籍,每一個圖書管理員負責其中一各區域。那圖書管理員則是一個抽象。由於圖書是客觀存在的,它不會由於圖書管理員的離開而消失。。也就是說咱們能夠經過實現的子類和抽象的子類進行組合,可得出任意形狀的系統。使用橋接模式。圖書區內上架什麼書或者下架什麼書,對圖書管理員不會產生影響(只要保持方法穩定)。
1.實現的基類(UML類圖中的Implementor)
#ifndef IMPLEMENTOR_H_ #define IMPLEMENTOR_H_ class Implementor { public: virtual void display()=0; Implementor() = default; virtual ~Implementor() = default; }; #endif
2.實現的具體類(UML類圖中的ConcreteImplementor)
#ifndef IMPLEMENTOR1_H_ #define IMPLEMENTOR1_H_ #include "Implementor.h" #include <iostream> class Implementor1:public Implementor { public: void display() override; Implementor1() = default; ~Implementor1() = default; }; #endif #include "Implementor1.h" void Implementor1::display() { std::cout << "Book1 " << std::endl; }
3.抽象的基類(UML類圖中的Abstraction)
#ifndef ABSTRACT_H_ #define ABSTRACT_H_ #include "Implementor.h" class Abstract { public: virtual void sell() = 0; Abstract() = default; virtual ~Abstract() = default; protected: Implementor* m_pobjImplementor{nullptr}; }; #endif
4.抽象的具體類(UML類圖中的RefinedAbstraction)
#ifndef REFINEDABSTRACTION1_H_ #define REFINEDABSTRACTION1_H_ #include "Abstract.h" #include <string> #include <iostream> class RefinedAbstraction1:public Abstract { public: void sell() override; RefinedAbstraction1(std::string strName,Implementor* objImplementor): m_strName(strName) { m_pobjImplementor = objImplementor; } private: std::string m_strName; }; #endif #include "RefinedAbstraction1.h" void RefinedAbstraction1::sell() { if(nullptr != m_pobjImplementor) { std::cout << "My name is:" << m_strName<<".I am responsible for " << std::endl; m_pobjImplementor->display(); } }
5.客戶端代碼(main)
#include "RefinedAbstraction1.h" #include "Implementor1.h" #include "Abstract.h" int main(int argc,char *aargv[]) { Implementor1 objConcreteImplement; RefinedAbstraction1 concreteAbstraction("Yang",&objConcreteImplement); Abstract *ab = &concreteAbstraction; ab->sell(); return (1); }