設計模式---建造者模式

一.概述
建造者模式(Builder Pattern):將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。建造者模式是一種對象創建型模式,又稱爲生成器模式,它是一種較爲複雜、使用頻率也相對較低的創建型模式。建造者模式爲客戶端返回的不是一個簡單的產品,而是一個由多個部件組成的複雜產品。舉個簡單的例子,比如我們去買電腦,買的是成品而不是散裝的零件。

產品的內部表象
一個產品常有不同的組成成分作爲產品的零件,這些零件有可能是對象,也有可能不是對象,它們通常又叫做產品的內部表象(internal representation)。不同的產品可以有不同的內部表象,也就是不同的零件。使用建造模式可以使客戶端不需要知道所生成的產品有哪些零件,每個產品的對應零件彼此有何不同,是怎麼建造出來的,以及怎麼組成產品。

對象性質的建造
有些情況下,一個對象會有一些重要的性質,在它們沒有恰當的值之前,對象不能作爲一個完整的產品使用。比如,一個電子郵件有發件人地址、收件人地址、主題、內容、附錄等部分,而在最起碼的收件人地址得到賦值之前,這個電子郵件不能發送。

有些情況下,一個對象的一些性質必須按照某個順序賦值纔有意義。在某個性質沒有賦值之前,另一個性質則無法賦值。這些情況使得性質本身的建造涉及到複雜的商業邏輯。這時候,此對象相當於一個有待建造的產品,而對象的這些性質相當於產品的零件,建造產品的過程是建造零件的過程。由於建造零件的過程很複雜,因此,這些零件的建造過程往往被“外部化”到另一個稱做建造者的對象裏,建造者對象返還給客戶端的是一個全部零件都建造完畢的產品對象。

建造模式利用一個導演者對象和具體建造者對象一個個地建造出所有的零件,從而建造出完整的產品對象。建造者模式將產品的結構和產品的零件的建造過程對客戶端隱藏起來,把對建造過程進行指揮的責任和具體建造者零件的責任分割開來,達到責任劃分和封裝的目的。

在這裏插入圖片描述
在建造者模式結構圖中包含如下幾個角色:
● Builder(抽象建造者):它爲創建一個產品Product對象的各個部件指定抽象接口,在該接口中一般聲明兩類方法,一類方法是buildPartX(),它們用於創建複雜對象的各個部件;另一類方法是getResult(),它們用於返回複雜對象。Builder既可以是抽象類,也可以是接口。

●ConcreteBuilder(具體建造者):它實現了Builder接口,實現各個部件的具體構造和裝配方法,定義並明確它所創建的複雜對象,也可以提供一個方法返回創建好的複雜產品對象。

●Product(產品角色):它是被構建的複雜對象,包含多個組成部件,具體建造者創建該產品的內部表示並定義它的裝配過程。

● Director(指揮者):指揮者又稱爲導演類,它負責安排複雜對象的建造次序,指揮者與抽象建造者之間存在關聯關係,可以在其construct()建造方法中調用建造者對象的部件構造與裝配方法,完成複雜對象的建造。客戶端一般只需要與指揮者進行交互,在客戶端確定具體建造者的類型,並實例化具體建造者對象(也可以通過配置文件和反射機制),然後通過指揮者類的構造函數或者Setter方法將該對象傳入指揮者類中。

導演者角色是與客戶端打交道的角色。導演者將客戶端創建產品的請求劃分爲對各個零件的建造請求,再將這些請求委派給具體建造者角色。具體建造者角色是做具體建造工作的,但是卻不爲客戶端所知。

一般來說,每有一個產品類,就有一個相應的具體建造者類。這些產品應當有一樣數目的零件,而每有一個零件就相應地在所有的建造者角色裏有一個建造方法。這裏就舉買電腦的例子來介紹,我們假設電腦需要2個組件,主機和顯示器。

二.代碼示例

@Data
public class Computer {
    private String host;//主機
    private String display;// 顯示屏
}

public interface Builder {
    void buildHost();
    void buildDisplay();
    Computer retrieveResult();
}

public class LenovoBuilder implements Builder {

    Computer computer = new Computer();
    /**
     * 產品零件建造方法1
     */
    @Override
    public void buildDisplay() {
        //構建產品的第一個零件
        computer.setDisplay("聯想顯示器");
    }

    /**
     * 產品零件建造方法1
     */
    @Override
    public void buildHost() {
        //構建產品的第二個零件
        computer.setHost("聯想主機");
    }

    /**
     * 產品返還方法
     */
    @Override
    public Computer retrieveResult() {
        return computer;
    }
}

public class HuaweiBuilder implements  Builder{
    Computer computer = new Computer();

    /**
     * 產品零件建造方法1
     */
    @Override
    public void buildDisplay() {
        //構建產品的第一個零件
        computer.setDisplay("華爲顯示器");
    }

    /**
     * 產品零件建造方法1
     */
    @Override
    public void buildHost() {
        //構建產品的第二個零件
        computer.setHost("華爲主機");
    }
    /**
     * 產品返還方法
     */
    @Override
    public Computer retrieveResult() {
        return computer;
    }
}

public class Director {
    /**
     * 持有當前需要使用的建造器對象
     */
    private Builder builder;
    /**
     * 構造方法,傳入建造器對象
     * @param builder 建造器對象
     */
    public Director(Builder builder){
        this.builder = builder;
    }
    /**
     * 產品構造方法,負責調用各個零件建造方法
     */
    public void construct(){
        builder.buildHost();
        builder.buildDisplay();
    }
}
public class Client {
    public static void main(String[]args){
        Builder builder = new LenovoBuilder();
        Director director = new Director(builder);
        director.construct();
        Computer computer = builder.retrieveResult();
        System.out.println(computer.getHost());
        System.out.println(computer.getDisplay());
    }
}

以上代碼就是模擬建造者模式的使用場景,其中電腦銷售人員相當於指揮者,只要客戶確定電腦的類型,電腦銷售人員可以通知電腦組裝人員給客戶組裝一臺電腦。
在這裏插入圖片描述
客戶端負責創建導演者和具體建造者對象。然後,客戶端把具體建造者對象交給導演者,導演者操作具體建造者,開始創建產品。當產品完成後,建造者把產品返還給客戶端。

把創建具體建造者對象的任務交給客戶端而不是導演者對象,是爲了將導演者對象與具體建造者對象的耦合變成動態的,從而使導演者對象可以操縱數個具體建造者對象中的任何一個。

三.JDK中建造者模式的應用
StringBuilder和StringBuffer的append()方法使用了建造者模式。
StringBuilder把構建者的角色交給了其父類AbstractStringBuilder。

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence{
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}

四.總結
建造者模式的核心在於如何一步步構建一個包含多個組成部件的完整對象,使用相同的構建過程構建不同的產品,在軟件開發中,如果我們需要創建複雜對象並希望系統具備很好的靈活性和可擴展性可以考慮使用建造者模式。

1.主要優點
在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。

每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象。由於指揮者類針對抽象建造者編程,增加新的具體建造者無須修改原有類庫的代碼,系統擴展方便,符合“開閉原則”

可以更加精細地控制產品的創建過程。將複雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。

2.主要缺點
建造者模式所創建的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,例如很多組成部分都不相同,不適合使用建造者模式,因此其使用範圍受到一定的限制。

如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,增加系統的理解難度和運行成本。

3.適用場景
需要生成的產品對象有複雜的內部結構,這些產品對象通常包含多個成員屬性。

需要生成的產品對象的屬性相互依賴,需要指定其生成順序。

對象的創建過程獨立於創建該對象的類。在建造者模式中通過引入了指揮者類,將創建過程封裝在指揮者類中,而不在建造者類和客戶類中。

隔離複雜對象的創建和使用,並使得相同的創建過程可以創建不同的產品。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章