設計模式 — 建造者模式

介紹

將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示

在用戶不知道對象的建造過程和細節的情況下就可以直接創建複雜的對象。用戶只需要給出指定複雜對象的類型和內容,建造者模式負責按順序創建複雜對象(把內部的建造過程和細節隱藏起來)

  • 核心

    image

建造者模式的四個角色

  1. Product (產品角色) :一個具體的產品對象。
  1. Builder(抽象建造者):創建一個Product對象的各個部件指定的介面/抽象類。
  2. ConcreteBuilder(具體建造者):實現介面,構建和裝配各個部件。
  3. Director(指揮者):構建一個使用Builder介面的對象。它主要是用於創建一個複雜的對象。它主要有兩個作用,一是:隔離了客戶與對象的生產過程,二是:負責控制產品對象的生產過程

  • 優點:建造者獨立,易擴展,便於控制細節風險

  • 缺點:產品必須有共同點,範圍有限制,如內部變化複雜,會有很多的建造類。

建造者模式的注意事項和細節

  1. 客戶端(使用程式)不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象

  2. 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產品對象

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

  4. 增加新的具體建造者無須修改原有類庫的程式碼,指揮者類針對抽象建造者類編程,系統擴展方便,符合「開閉原則」

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

  6. 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大,因此在這種情況下,要考慮是否選擇建造者模式.

  7. 抽象工廠模式 vs 建造者模式
    抽象工廠模式實現對產品家族的創建,一個產品家族是這樣的一系列產品:具有不同分類維度的產品組合,採用抽象工廠模式不需要關心構建過程,只關心什麼產品由什麼工廠生產即可。

    而建造者模式則是要求按照指定的藍圖建造產品,它的主要目的是通過組裝零配件而產生一個新產品

使用場景

  • 需要生成的對象具有複雜的內部結構

  • 需要生成的對象內部屬性本身相互依賴

案例

image

// 產品
public class House {

    private String bisic;
    private String walls;
    private String roofed;

    public String getBisic() {
        return bisic;
    }

    public void setBisic(String bisic) {
        this.bisic = bisic;
    }

    public String getWalls() {
        return walls;
    }

    public void setWalls(String walls) {
        this.walls = walls;
    }

    public String getRoofed() {
        return roofed;
    }

    public void setRoofed(String roofed) {
        this.roofed = roofed;
    }
}

// 抽象的建造者
public abstract class HouseBuilder {

    private House house = new House();

    abstract void buildBisic();
    abstract void buildWalls();
    abstract void roofed();

    public House build(){
        return house;
    }

}

// 具體建造者
public class HighHouse extends HouseBuilder {

    @Override
    void buildBisic() {
        System.out.println("高房 打地基 10米");
    }

    @Override
    void buildWalls() {
        System.out.println("高房 刷粉 20cm");
    }

    @Override
    void roofed() {
        System.out.println("高房 封頂");
    }

}

// 具體建造者
public class CommonHouse extends HouseBuilder {
    @Override
    void buildBisic() {
        System.out.println("普通房子 打地基 5米");
    }

    @Override
    void buildWalls() {
        System.out.println("普通房子 刷粉 5cm");
    }

    @Override
    void roofed() {
        System.out.println("普通房子 封頂");
    }
}

// 指揮者,在這裡指訂製作流程,返回產品
public class HouseDirector {

    private HouseBuilder houseBuilder;

    public HouseBuilder getHouseBuilder() {
        return houseBuilder;
    }

    public void setHouseBuilder(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    public HouseDirector(){

    }

    public HouseDirector(HouseBuilder houseBuilder){
        this.houseBuilder = houseBuilder;
    }

    // 處理建造流程
    public House constructHouse(){
        houseBuilder.buildBisic();
        houseBuilder.buildWalls();
        houseBuilder.roofed();
        return houseBuilder.build();
    }
}

public class Client {

    public static void main(String[] args){

        // 具體建造者
        CommonHouse commonHouse = new CommonHouse();
        // 指揮者
        HouseDirector houseDirector = new HouseDirector(commonHouse);
        // 產品
        House house1 = houseDirector.constructHouse();

        System.out.println("-------------------");

        houseDirector.setHouseBuilder(new HighHouse());

        House house2 = houseDirector.constructHouse();
    }

}

// 測試
/*

普通房子 打地基 5米
普通房子 刷粉 5cm
普通房子 封頂
-------------------
高房 打地基 10米
高房 刷粉 20cm
高房 封頂

*/