【設計模式】- 生成器模式(Builder)

黑米麵包派發表於2021-04-13

生成器模式

建造者模式、Builder

生成器模式 也叫建造者模式,可以理解成可以分步驟建立一個複雜的物件。在該模式中允許你使用相同的建立程式碼生成不同型別和形式的物件。

生成器的結構模式

  1. 生成器(Builder)介面宣告在所有型別生成器中通用的產品構造的步驟
  2. 具體的生成器(ConcreteBuilders)提供構造過程的不同實現。 具體生成器也可以構造不遵循通用介面的產品。
  3. 產品 (Products) 是最終生成的物件。 由不同生成器構造的產品無需屬於同一類層次結構或介面。
  4. 主管 (Director) 類定義呼叫構造步驟的順序, 這樣你就可以建立和複用特定的產品配置。
  5. 客戶端 (Client) 必須將某個生成器物件與主管類關聯。 一般情況下, 你只需通過主管類建構函式的引數進行一次性關聯即可。 此後主管類就能使用生成器物件完成後續所有的構造任務。 但在客戶端將生成器物件傳遞給主管類製造方法時還有另一種方式。 在這種情況下, 你在使用主管類生產產品時每次都可以使用不同的生成器。

案例分析

下面我們將結合一輛汽車的製造過程來模擬一個構建構成。針對汽車這種非常複雜的機械結構,我們需要將汽車各個零部件的組裝過程抽取到不同的程式碼中,最終組成一個完成的產品。下面我們將簡化這個過程,模擬一輛汽車的車型產品,命名,顏色噴漆,產品定價等資訊。

核心類解釋

  • 抽象出一個汽車產品Car
  • 定義Builder介面,規定Car的構建步驟和過程。
  • CarBuilder實現類。
  • CarDirectror統一構建過程。

程式碼實現

Car.class

public class Car {
    /**
     * 車型 SUV MVP 轎車等
     */
    private String type;
    /**
     * 汽車顏色
     */
    private String color;
    /**
     * 奧迪 啥的
     */
    private String name;
    /**
     * 售價
     */
    private BigDecimal price;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "type='" + type + '\'' +
                ", color='" + color + '\'' +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

Builder.class

public interface Builder {
    /**
     * 定義車型
     * @param type
     * @return
     */
    Builder buildType(String type);

    /**
     * 定義產品名稱
     * @param name
     * @return
     */
    Builder buildName(String name);

    /**
     * 確定顏色噴漆
     * @param color
     * @return
     */
    Builder buildColor(String color);

    /**
     * 定價
     * @param bigDecimal
     * @return
     */
    Builder buildPrice(BigDecimal bigDecimal);

    /**
     * 返回
     * @return
     */
    Car build();
}

CarBuilder.class

public class CarBuilder implements Builder{
    private final Car car = new Car();

    @Override
    public Builder buildColor(String color) {
        car.setColor(color);
        return this;
    }

    @Override
    public Builder buildType(String type) {
        car.setType(type);
        return this;
    }

    @Override
    public Builder buildName(String name) {
        car.setName(name);
        return this;
    }

    @Override
    public Builder buildPrice(BigDecimal bigDecimal) {
        car.setPrice(bigDecimal);
        return this;
    }

    @Override
    public Car build() {
        return car;
    }
}

這裡的處理方式只是做解釋,其實還是可以進一步抽象CarBuilder到具體車型的Builder,並在次基礎上新增一些驗證的功能

CarDirector.class

public class CarDirector {

    public void mpvCarBuilder(Builder builder){
        builder.buildName("奧迪");
        builder.buildType("mpv");
        builder.buildColor("red");
        builder.buildPrice(new BigDecimal("400000.00"));
    }

    public void suvCarBuilder(Builder builder){
        builder.buildName("奧迪");
        builder.buildType("suv");
        builder.buildColor("black");
        builder.buildPrice(new BigDecimal("300000.00"));
    }
}

Client.class

public class Client {
    @Test
    public void builderMvp(){
        CarDirector carDirector = new CarDirector();
        Builder builder = new CarBuilder();
        carDirector.mpvCarBuilder(builder);
        System.out.println(builder.build().toString());
    }

    @Test
    public void buildSuv(){
        CarDirector carDirector = new CarDirector();
        Builder builder = new CarBuilder();
        carDirector.suvCarBuilder(builder);
        System.out.println(builder.build().toString());
    }
}

總結

在日常開發中我們能經常用到Builder設計模式,最常見的就是核心程式中的StringBuilder了,在開源框架中我們也經常能夠看到,例如Mybatis中的SqlSourceBuilderXMLConfigBuilder等等資訊

為了靈活構造複雜物件,該物件會有多個成員變數,在外部呼叫的時候,不需要或者不方便一次性建立出所有的成員變數,在這種情況下,使用多個構造方法去構建物件,很難維護,這時候Builder設計模式解決這個問題,進行buid()方法中建立物件,並且將builder傳入,該builder中,維護了傳入物件的成員變數。

相關文章