Java 設計模式(五):建造者模式

建造者模式

建造者模式(Builder),又叫生成器模式,是一種對象構建模式。它將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
建造者模式可以將一個產品的內部表象和產品的生成過程分割開來,從而可以使一個建造過程生成具有不同的內部表象的產品對象。如果我們用了建造者模式,那麼用戶就只需指定需要建造的類型就可以得到它們,而具體建造的過程和細節就不需要知道了。

建造者模式解析

結構圖

角色介紹

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

建造者模式基本代碼

  • Product 類:產品類,由多個部件組成。
public class Product {

    private List<String> parts = new ArrayList<>();

    /**
     * 添加部件
     */
    public void add(String part) {
        this.parts.add(part);
    }

    /**
     * 列舉所有部件
     */
    public void show() {
        this.parts.forEach(System.out::println);
    }
}
  • Builder 類:抽象建造者類,確定產品由兩個部件 PartA 和 PartB 組成,並聲明一個得到產品結果的方法 getResult()。
public interface Builder {

    void buildPartA();

    void buildPartB();

    Product getResult();
}
  • ConcreteBuilderA 類:具體建造者 A。
public class ConcreteBuilderA implements Builder {

    private Product product = new Product();

    @Override
    public void buildPartA() {
        product.add("X");
    }

    @Override
    public void buildPartB() {
        product.add("Y");
    }

    @Override
    public Product getResult() {
        return product;
    }
}
  • ConcreteBuilderB 類:具體建造者 B。
public class ConcreteBuilderB implements Builder {

    private Product product = new Product();

    @Override
    public void buildPartA() {
        product.add("M");
    }

    @Override
    public void buildPartB() {
       product.add("N");
    }

    @Override
    public Product getResult() {
        return product;
    }
}
  • Director 類:指揮者類。
public class Director {

    public void build(Builder builder) {
        builder.buildPartA();
        builder.buildPartB();
    }
}
  • Main 類
public class Main {

    public static void main(String[] args) {
        Director director = new Director();

        ConcreteBuilderA builderA = new ConcreteBuilderA();
        ConcreteBuilderB builderB = new ConcreteBuilderB();

        director.build(builderA);
        Product resultA = builderA.getResult();
        resultA.show();

        director.build(builderB);
        Product resultB = builderB.getResult();
        resultB.show();
    }
}

示例

需求:蓋房子,過程有打樁、砌牆、封頂。房子有各種各樣的,比如普通房,高樓,別墅,各種房子的過程雖然一樣,但是要求不相同的。

傳統寫法

/**
 * House
 */
public class House {

    private Integer length;

    private Integer width;

    private Integer high;

    public Integer getLength() {
        return length;
    }

    public void setLength(Integer length) {
        this.length = length;
    }

    public Integer getWidth() {
        return width;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }

    public Integer getHigh() {
        return high;
    }

    public void setHigh(Integer high) {
        this.high = high;
    }

    @Override
    public String toString() {
        return "House{" +
                "length=" + length +
                ", width=" + width +
                ", high=" + high +
                '}';
    }
}

/**
 * 普通房子
 */
public class CommonHouseBuilder {
    
    public House build() {
        House house = new House();
        house.setLength(50);
        house.setWidth(20);
        house.setHigh(5);

        return house;
    }
}

/**
 * 高房子
 */
public class HighHouseBuilder {

    public House build() {
        House house = new House();
        house.setLength(60);
        house.setWidth(30);
        house.setHigh(6);

        return house;
    }
}

/**
 * Main
 */
public class Main {

    public static void main(String[] args) {
        // 普通房子
        CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
        House commonHouse = commonHouseBuilder.build();
        System.out.println(commonHouse.toString());

        // 高房子
        HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
        House highHouse = highHouseBuilder.build();
        System.out.println(highHouse.toString());

    }
}

上面這種寫法將建造過程和表象都放在了一起,耦合性很強,而且普通房子和高房子的建造過程是一樣的,只是內部的細節不同,代碼是可以複用的。如果我們又要進行別墅的建造,建造過程我們又要重新寫一遍,而且很容易漏寫步驟。所以讓我們使用建造者模式改進。

使用建造者模式改進

/**
 * House
 */
public class House {

    private Integer length;

    private Integer width;

    private Integer high;

    public Integer getLength() {
        return length;
    }

    public void setLength(Integer length) {
        this.length = length;
    }

    public Integer getWidth() {
        return width;
    }

    public void setWidth(Integer width) {
        this.width = width;
    }

    public Integer getHigh() {
        return high;
    }

    public void setHigh(Integer high) {
        this.high = high;
    }

    @Override
    public String toString() {
        return "House{" +
                "length=" + length +
                ", width=" + width +
                ", high=" + high +
                '}';
    }
}

/**
 * Builder
 */
public interface Builder {

    void buildPartA();

    void buildPartB();

    Product getResult();
}

/**
 * 普通房子建造者
 */
public class CommonHouseBuilder implements HouseBuilder {

    private House house = new House();

    @Override
    public void buildHigh() {
        house.setHigh(5);
    }

    @Override
    public void buildWidth() {
        house.setWidth(20);
    }

    @Override
    public void buildLength() {
       house.setLength(50);
    }

    @Override
    public House getResult() {
        return house;
    }
}

/**
 * 高房子建造者
 */
public class HighHouseBuilder implements HouseBuilder {

    private House house = new House();

    @Override
    public void buildHigh() {
        house.setHigh(6);
    }

    @Override
    public void buildWidth() {
        house.setWidth(30);
    }

    @Override
    public void buildLength() {
        house.setLength(60);
    }

    @Override
    public House getResult() {
        return house;
    }
}

/**
 * HouseDirector
 */
public class HouseDirector {

    public void buildHouse(HouseBuilder houseBuilder) {
        houseBuilder.buildHigh();
        houseBuilder.buildLength();
        houseBuilder.buildWidth();
    }
}

/**
 * Main
 */
public class Main {

    public static void main(String[] args) {
        HouseDirector houseDirector = new HouseDirector();
        // 普通房子
        CommonHouseBuilder commonHouseBuilder = new CommonHouseBuilder();
        houseDirector.buildHouse(commonHouseBuilder);
        House commonHouse = commonHouseBuilder.getResult();
        System.out.println(commonHouse.toString());

        // 高房子
        HighHouseBuilder highHouseBuilder = new HighHouseBuilder();
        houseDirector.buildHouse(highHouseBuilder);
        House highHouse = highHouseBuilder.getResult();
        System.out.println(highHouse.toString());

    }
}

小結

建造者模式,主要用於創建一些複雜的對象,這些對象內部構建間的建造順序通常是穩定的,但對象內部的構建通常面臨複雜的變化。而建造者模式的好處就是使得建造代碼與表示代碼分離,由於建造者隱藏了該產品的構建過程,所以如果要改變一個產品內部的表示,只需再定義一個具體的建造者就可以了。

最後,建造者模式是逐步建造產品的,所以建造者的 Builder 類裏的那些建造方法必須是足夠普遍的,以便爲各類型的具體建造者構造。如果產品的差異性較大,就不適合使用建造者模式。

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