1. 程式人生 > >再談設計模式之建造者模式

再談設計模式之建造者模式

我總喜歡隔一段時間就來學習學習設計模式,每當業務程式碼寫得感覺有點累的時候就喜歡考慮一下是否可以優化一下結構,尤其是當寫到重複性的程式碼,總想著把它複用起來,一種情況是在開發之前就設計好可複用的模組,另一種是被動的在專案當中寫到重複的程式碼的時候再去考慮程式碼的重構達到良好的複用。而複用的兩種方式主要是繼承和組合,當然在大部分情況下,設計原則指引我們更多采用組合的方式,其實各有各的優勢,繼承有更明確的類之間關係,缺點就是暴露了類的實現細節,組合遮蔽了物件的細節,能夠更加鬆散的耦合。

最近又重新溫習了建造者模式和中介者模式,建造者模式呢也是一種建立型設計模式,如果一個物件很複雜,而這種複雜性更多體現在它的屬性的複雜性,複雜性可以是屬性本身繁瑣的組裝,或則是屬性的組合很多,這個時候使用建造者模式是很好的一種方式,建立者能夠將複雜物件的組裝流程和組裝的具體屬性接耦開。

這裡寫圖片描述
- 物件的組裝流程
產品類Product : 假裝它是一個很複雜的物件,包含很多複雜的屬性,而且各個屬性都有很多種組合。
導演類Director:這個導演就是負責裝配流程的,它不關心各個具體的屬性的建立,而是關注整個屬性的裝配工作。
建造類Builder: 它可以是一個介面或則是抽象類,它負責具體的產品屬性的構造細節。

我們可以來寫一個複雜的物件,就假設我們生產的產品是一個iphone,它定義如下:

class Iphone {

    private String cpu;

    private String dispaly;

    // 省略setter getter toString

iphone 的處理器和顯示屏可以有多種組合:

        Iphone iphone = new Iphone();

        iphone.setCpu("臺積電");
        iphone.setDispaly("三星");
        System.out.println(iphone);

        iphone.setCpu("三星");
        iphone.setDispaly("LG");
        System.out.println(iphone);

輸出如下:

Iphone [cpu=臺積電, dispaly=三星]
Iphone [cpu=三星, dispaly=LG]

我們的iphone是十分複雜的,如果它的屬性很多,我們使用的時候每次都要去拼裝屬性,肯定會瘋掉,蘋果公司也不傻,不會把雞蛋放在一個籃子裡,所以每次搭配都會有固定的一些搭配,例如三星的處理器就不太可能再去買三星的顯示器了。這些固定的搭配我們在使用的時候每次都去拼裝感覺是沒必要的。我們採用建造者模式來重構。
建造類:

abstract class Builder {

    abstract String getCpu();

    abstract String getDisplay();
}

具體的裝配“套餐“:


class Builder1 extends Builder {

    @Override
    String getCpu() {
        return "臺積電";
    }

    @Override
    String getDisplay() {
        return "三星";
    }

}

class Builder2 extends Builder {

    @Override
    String getCpu() {
        return "三星";
    }

    @Override
    String getDisplay() {
        return "LG";
    }

}

導演類,負責裝配流程:

class Director {

    private Builder builder;

    public Director(Builder builder) {
        super();
        this.builder = builder;
    }

    public Iphone BuilderIphone() {
        Iphone iphone = new Iphone();
        // 負責裝配屬性
        iphone.setCpu(builder.getCpu());
        // 裝配中途我休息會兒
        System.out.println("我正在裝配iphone");
        iphone.setDispaly(builder.getDisplay());
        return iphone;
    }

    public void setBuilder(Builder builder) {
        this.builder = builder;
    }

}

使用者使用:

        // 使用者使用方便很多
        Builder builder = new Builder1();
        Director director = new Director(builder);
        Iphone iphone = director.BuilderIphone();
        System.out.println(iphone);

        builder = new Builder2();
        director.setBuilder(builder);
        iphone = director.BuilderIphone();
        System.out.println(iphone);

輸出如下:

我正在裝配iphone
Iphone [cpu=臺積電, dispaly=三星]
我正在裝配iphone
Iphone [cpu=三星, dispaly=LG]

我如果要新的組合方式,我只需要繼承Builder再實現一個就好,不用關心組裝過程,使用的時候也更加方便。

我們再來總結一下:
建造者模式解決的問題就是在於建造物件的複雜性,這和工廠模式不太一樣,工廠強調的是物件的建立和物件的使用的接耦,對於物件的建立細節並沒有明確的要求,建造者模式的關注點更多在於需要使用的這個物件本身的複雜性問題,各種設計模式或多或少會有類似的結構,因為它們背後的指導原則都是設計模式幾大原則,因此為了滿足這些原則作出一些類似的設計是很正常的,但是它們的側重點不同的關注點,設計模式的難點也不在於理解它的設計思想,而在於理解它的使用場景,這就要求設計者理解使用場景,理解模式本身,才談得上活用設計模式。