設計模式(十一)——橋接模式

設計模式(十一)——橋接模式

1、橋接模式簡介

1、橋接模式簡介

    橋接模式將抽象(Abstraction)與實現(Implementation)分離,使得兩者能夠獨立地變化。ios

    橋接模式將抽象和實現分別獨立實現,Abstraction類和Implement類。編程

    橋接模式中的實現不是指抽象基類的具體子類對抽象基類中虛函數(接口)的實現,是怎麼去實現用戶的需求,即在Implement具體類中實現Abstraction的接口功能,而且是經過組合(委託)的方式實現的,所以橋接模式實現不是指的繼承基類、實現基類接口,而是指的是經過對象組合實現用戶的需求。設計模式

wKioL1nSb_WAs0M_AACnJ7I-BwI099.jpg

    橋接模式將繼承關係轉換爲組合關係,從而下降了系統間的耦合,減小了代碼編寫量。使用組合(委託)的方式將抽象和實現完全地解耦,好處是抽象和實現能夠分別獨立地變化,系統的耦合性也獲得了很好的下降。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所定義操做的接口,由其具體派生類ConcreteImplemenAConcreteImplemenB或者其餘派生類實現。

三、橋接模式優缺點

    優勢:

    A分離接口及其實現部分 一個實現未必不變地綁定在一個接口上。抽象類的實現能夠在運行時刻進行配置,一個對象甚至能夠在運行時刻改變它的實現。將AbstractionImplement分離有助於下降對實現部分編譯時刻的依賴性,當改變一個實現類時,並不須要從新編譯Abstraction類和它的客戶程序。爲了保證一個類庫的不一樣版本之間的二進制兼容性,必定要有這個性質。另外,接口與實現分離有助於分層,從而產生更好的結構化系統,系統的高層部分僅需知道AbstractionImplement便可。
    B提升可擴充性 能夠獨立地對AbstractionImplement層次結構進行擴充。

 C實現細節對客戶透明 能夠對客戶隱藏實現細節,例如共享Implement對象以及相應的引用計數機制。

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

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

    缺點

 A橋接模式的引入會增長系統的理解與設計難度,因爲聚合關聯關係創建在抽象層,要求開發者針對抽象進行設計與編程。

 B橋接模式要求正確識別出系統中兩個獨立變化的維度,所以其使用範圍具備必定的侷限性。

    C客戶必須知道選擇哪種類型的實現。

4、橋接模式使用場景

    橋接模式使用場景
    A當一個對象有多個變化因素的時候,考慮依賴於抽象的實現,而不是具體的實現。手機品牌有2種變化因素,一個是品牌,一個是功能。

 B當多個變化因素在多個對象間共享時,考慮將變化的部分抽象出來再聚合或組合進來。

 C當考慮一個對象的多個變化因素能夠動態變化的時候,考慮使用橋接模式,如手機的手機品牌是變化的,手機的功能也是變化的,因此將每一個可變化的因數分離出來,獨立的變化。

    抽象工廠模式能夠用來建立和配置一個特定的橋接模式。

    適配器模式用來幫助無關的類協同工做,一般在系統設計完成後纔會被使用。然而,橋接模式則是在系統開始時就被使用,使得抽象接口和實現部分能夠獨立進行改變。

       橋接模式和裝飾模式在必定程度上都是爲了減小子類的數目,避免出現複雜的繼承關係但解決的方法卻各有不一樣裝飾模式把子類中比基類中多出來的部分放到單獨的類裏面,以適應新功能增長的須要,當把描述新功能的類封裝到基類的對象裏面時,就獲得所須要的子類對象,描述新功能的類經過組合能夠實現不少的功能組合 橋接模式則把原來的基類的實現化細節抽象出來,在構造到一個實現化的結構中,而後再把原來的基類改形成一個抽象化的等級結構,就能夠實現系統在多個維度上的獨立變化 。

2、橋接模式實現

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;
}


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

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

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

3、橋接模式實例

一、計算機實例

電腦品牌和操做系統是兩個概念,不一樣的品牌的電腦能夠安裝相同或不一樣的操做系統,二者都具備很大的變更性。若是單獨以電腦品牌或操做系統爲基類來進行繼承擴展的話,會使類的數目劇增而且耦合性很高,若是更改電腦品牌或增長操做系統類型都會增長不少的變更

    將二者抽象出來兩個基類分別是ComputerOS,在Computer類中聚合一個OS對象的基類將解決電腦品牌操做系統擴展混亂的問題,二者的擴展就相對靈活,剪短了二者的必要聯繫

wKiom1nScG_QBJ0pAACDv_wMIUw967.jpg

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;
}
相關文章
相關標籤/搜索