java-23種設計模式-橋樑模式

1 引子

下面是呂振宇大牛的一個例子,我的以爲挺好的,有助於理解Bridge模式的設計目的:bash

設想要繪製一幅圖畫,藍天、白雲、綠樹、小鳥,若是畫面尺寸很大,那麼用蠟筆繪製就會遇到點麻煩。畢竟細細的蠟筆要塗出一片藍天,是有些麻煩。若是 有可能,最好有套大號蠟筆,粗粗的蠟筆很快能塗抹完成。至於色彩嗎,最好每種顏色來支粗的,除了藍天還有綠地呢。這樣,若是一套12種顏色的蠟筆,咱們需 要兩套24支,同種顏色的一粗一細。呵呵,畫還沒畫,開始作夢了:要是再有一套中號蠟筆就更好了,這樣,很少很多總共36支蠟筆。ide

再看看毛筆這一邊,竟然如此簡陋:一套水彩12色,外加大中小三支毛筆。你可別小瞧這"簡陋"的組合,畫藍天用大毛筆,畫小鳥用小毛筆,各具特點。函數

爲了一幅畫,咱們須要準備36支型號不一樣的蠟筆,而改用毛筆三支就夠了,固然還要搭 配上12種顏料。經過Bridge模式,咱們把乘法運算3×12=36改成了加法運算3+12=15,這一改進可不小。那麼咱們這裏蠟筆和毛筆到底有什麼 區別呢?
實際上,蠟筆和毛筆的關鍵一個區別就在於筆和顏色是否可以分離。【GOF95】橋樑模式的用意是"將抽象化 (Abstraction)與實現化(Implementation)脫耦,使得兩者能夠獨立地變化"。關鍵就在於可否脫耦。蠟筆的顏色和蠟筆自己是分不 開的,因此就形成必須使用36支色彩、大小各異的蠟筆來繪製圖畫。而毛筆與顏料可以很好的脫耦,各自獨立變化,便簡化了操做。在這裏,抽象層面的概念 是:"毛筆用顏料做畫",而在實現時,毛筆有大中小三號,顏料有紅綠藍等12種,因而即可出現3×12種組合。每一個參與者(毛筆與顏料)均可以在本身的自 由度上隨意轉換。this

​ 蠟筆因爲沒法將筆與顏色分離,形成筆與顏色兩個自由度沒法單獨變化,使得只有建立36種對象才能完成任務。Bridge 模式將繼承關係轉換爲組合關係,從而下降了系統間的耦合,減小了代碼編寫量。spa

2 橋樑模式的用意

​ 橋樑模式雖然不是一個使用頻率很高的模式,可是熟悉這個模式對於理解面向對象的設計原則,包括「開-閉」原則以及組合/聚合複用原則都頗有幫助。理解好這兩個原則,有助於造成正確的設計思想和培養良好的設計風格。設計

  橋樑模式的用意是「將抽象化(Abstraction)與實現化(Implementation)脫耦,使得兩者能夠獨立地變化」。這句話很短,可是第一次讀到這句話的人極可能都會思考良久而不解其意。3d

  這句話有三個關鍵詞,也就是抽象化、實現化和脫耦。理解這三個詞所表明的概念是理解橋樑模式用意的關鍵。code

  • 抽象化:cdn

    ​ 從衆多的事物中抽取出共同的、本質性的特徵,而捨棄其非本質的特徵,就是抽象化。例如蘋果、香蕉、生梨、 桃子等,它們共同的特性就是水果。得出水果概念的過程,就是一個抽象化的過程。要抽象,就必須進行比較,沒有比較就沒法找到在本質上共同的部分。共同特徵是指那些能把一類事物與他類事物區分開來的特徵,這些具備區分做用的特徵又稱本質特徵。所以抽取事物的共同特徵就是抽取事物的本質特徵,捨棄非本質的特徵。 因此抽象化的過程也是一個裁剪的過程。在抽象時,同與不一樣,決定於從什麼角度上來抽象。抽象的角度取決於分析問題的目的。對象

      一般狀況下,一組對象若是具備相同的特徵,那麼它們就能夠經過一個共同的類來描述。若是一些類具備相同的特徵,每每能夠經過一個共同的抽象類來描述。

  • 實現化:

    抽象化給出的具體實現,就是實現化。

    一個類的實例就是這個類的實例化,一個具體子類是它的抽象超類的實例化。

  • 脫耦:

    ​ 所謂耦合,就是兩個實體的行爲的某種強關聯。而將它們的強關聯去掉,就是耦合的解脫,或稱脫耦。在這裏,脫耦是指將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯。

      所謂強關聯,就是在編譯時期已經肯定的,沒法在運行時期動態改變的關聯;所謂弱關聯,就是能夠動態地肯定而且能夠在運行時期動態地改變的關聯。顯然,在Java語言中,繼承關係是強關聯,而聚合關係是弱關聯。

      將兩個角色之間的繼承關係改成聚合關係,就是將它們之間的強關聯改換成爲弱關聯。所以,橋樑模式中的所謂脫耦,就是指在一個軟件系統的抽象化和實現化之間使用聚合關係而不是繼承關係,從而使二者能夠相對獨立地變化。這就是橋樑模式的用意。

3 橋樑模式的結構

下圖所示就是一個實現了橋樑模式的示意性系統的結構圖:

能夠看出,這個系統含有兩個等級結構:

1、由抽象化角色和修正抽象化角色組成的抽象化等級結構。

2、由實現化角色和兩個具體實現化角色所組成的實現化等級結構。

  橋樑模式所涉及的角色有:

  ●  抽象化(Abstraction)角色:抽象化給出的定義,並保存一個對實現化對象的引用。

  ●  修正抽象化(RefinedAbstraction)角色:擴展抽象化角色,改變和修正父類對抽象化的定義。

  ●  實現化(Implementor)角色:這個角色給出實現化角色的接口,但不給出具體的實現。必須指出的是,這個接口不必定和抽象化角色的接口定義相同,實際上,這兩個接口能夠很是不同。實現化角色應當只給出底層操做,而抽象化角色應當只給出基於底層操做的更高一層的操做。

  ●  具體實現化(ConcreteImplementor)角色:這個角色給出實現化角色接口的具體實現。

​ 抽象化角色就像是一個水杯的手柄,而實現化角色和具體實現化角色就像是水杯的杯身。手柄控制杯身,這就是此模式別名「柄體」的來源。

​ 對象是對行爲的封裝,而行爲是由方法實現的。在這個示意性系統裏,抽象化等級結構中的類封裝了operation()方法;而實現化等級結構中的類封裝的是operationImpl()方法。固然,在實際的系統中每每會有多於一個的方法。

​ 抽象化等級結構中的方法經過向對應的實現化對象的委派實現本身的功能,這意味着抽象化角色能夠經過向不一樣的實現化對象委派,來達到動態地轉換本身的功能的目的。

4 代碼示例:

以公司生產產品爲例,我有一個公司,專門來生產銷售產品:

public abstract class Corp {

    //定義一個產品對象,抽象的了,不知道具體是什麼產品
    private Product product;
    //構造函數,由子類定義傳遞具體的產品進來
    public Corp(Product product){
        this.product = product;
    }
    //公司是幹什麼的?賺錢的呀,不賺錢傻子才幹
    public void makeMoney(){
        //每一個公司都是同樣,先生產
        this.product.beProducted();
        //而後銷售
        this.product.beSelled();
    }

}
複製代碼

總公司不幹活,只負責研發和收錢,總公司下有一個分公司,專門生產產品:

public class ShanZhaiCorp extends Corp {
    public ShanZhaiCorp(Product product) {
        super(product);
    }

    public void makeMoney(){
        super.makeMoney();
        System.out.println("我賺錢呀...");
    }

}
複製代碼

公司目前負責生產的產品有房子和衣服,什麼賺錢賣什麼。

產品類:

public abstract class Product {

    //甭管是什麼產品它總要是能被生產出來
    public abstract void beProducted();
    //生產出來的東西,必定要銷售出去,不然擴本呀
    public abstract void beSelled();

}
複製代碼

房子產品類:

public class House extends Product {
    @Override
    public void beProducted() {
        System.out.println("生產出的房子是這個樣子的...");
    }

    @Override
    public void beSelled() {
        System.out.println("生產出的房子賣出去了...");
    }
}
複製代碼

衣服產品類:

public class Clothes extends Product {
    @Override
    public void beProducted() {
        System.out.println("生產出的衣服是這個樣子的...");
    }

    @Override
    public void beSelled() {
        System.out.println("生產出的衣服賣出去了...");
    }
}
複製代碼

最後賣出去:

public class Client {

    public static void main(String[] args) {
        //山寨公司生產的產品不少,不過我只要指定產品就成了
        System.out.println("-------山寨公司是這樣運行的-------");
        System.out.println("生產衣服");
        ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes());
        shanZhaiCorp.makeMoney();
        System.out.println("生產房子");
        ShanZhaiCorp shanZhaiCorp1 = new ShanZhaiCorp(new House());
        shanZhaiCorp1.makeMoney();

    }

}
複製代碼

在這裏,後期無論怎麼增長新產品,都只須要根據Product進行擴張就能夠。

5 橋樑模式的優勢

  • 分離抽象和實現部分

    橋樑模式分離了抽象部分和實現部分,從而極大地提供了系統的靈活性。讓抽象部分和實現部分獨立出來,分別定義接口,這有助於對系統進行分層,從而產生更好的結構化的系統。

  • 更好的擴展性

    橋樑模式使得抽象部分和實現部分能夠分別獨立地擴展,而不會相互影響,從而大大提升了系統的可擴展性。

相關文章
相關標籤/搜索