Java設計模式-建造者模式

定義

Separate the construction of a complex object from its representation so that the sameconstruction process can create different representations.java

將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。git

實現

產品類

由多個部件組成設計模式

public class Product {

    private String partA;
    private String partB;

    public String getPartA() {
        return partA;
    }

    public void setPartA(String partA) {
        this.partA = partA;
    }

    public String getPartB() {
        return partB;
    }

    public void setPartB(String partB) {
        this.partB = partB;
    }

    @Override
    public String toString() {
        return "partA:" + partA + ", partB:" + partB;
    }
}
複製代碼

抽象建造者

規範產品的組建,通常是由子類實現。其中,buildPart方法是零件的配置,設置一個不一樣零件,或者不一樣的裝配順序就可能產生不一樣的產品。markdown

public abstract class Builder {

    /** * 設置產品的不一樣組件/零件,以得到不一樣的產品 */
    public abstract void buildPartA();

    /** * 設置產品的不一樣組件/零件,以得到不一樣的產品 */
    public abstract void buildPartB();

    /** * 建造產品 * @return */
    public abstract Product getProduct();

}
複製代碼

具體建造者

實現抽象類定義的全部方法,而且返回一個組建好的對象ide

public class ConcreteBuilder1 extends Builder {

    private Product product = new Product();

    @Override
    public void buildPartA() {
        System.out.println("ConcreteBuilder1->buildPartA()");
        product.setPartA("組件A1");
    }

    @Override
    public void buildPartB() {
        System.out.println("ConcreteBuilder1->buildPartB()");
        product.setPartB("組件B1");
    }

    @Override
    public Product getProduct() {
        System.out.println("ConcreteBuilder1->getProduct()");
        return product;
    }
}
複製代碼
public class ConcreteBuilder2 extends Builder {

    private Product product = new Product();

    @Override
    public void buildPartA() {
        System.out.println("ConcreteBuilder2->buildPartA()");
        product.setPartA("組件A2");
    }

    @Override
    public void buildPartB() {
        System.out.println("ConcreteBuilder2->buildPartB()");
        product.setPartB("組件B2");
    }

    @Override
    public Product getProduct() {
        System.out.println("ConcreteBuilder2->getProduct()");
        return product;
    }
}
複製代碼

導演類

也叫指揮者類,負責安排已有模塊的順序,而後告訴Builder開始建造。導演類起到封裝的做用,避免高層模塊深刻到建造者內部的實現類。在建造者模式比較龐大時,導演類能夠有多個。oop

public class Director {

    private Builder builder;

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

    /** * 將部件partA、partB...最後組成複雜對象(使用多個簡單的對象一步一步構建成一個複雜的對象) */
    public void construct(){
        builder.buildPartA();
        builder.buildPartB();
    }
}
複製代碼

客戶端代碼

public class Client {

    public static void main(String[] args) {
        Builder builder1 = new ConcreteBuilder1();
        Director director1 = new Director(builder1);
        director1.construct();
        Product product1 = builder1.getProduct();
        System.out.println(product1);

        Builder builder2 = new ConcreteBuilder2();
        Director director2 = new Director(builder2);
        director2.construct();
        Product product2 = builder2.getProduct();
        System.out.println(product2);
    }
}
複製代碼

優勢

  • 封裝性ui

    客戶端沒必要知道產品內部組成的細節this

  • 建造者獨立,容易擴展spa

  • 便於控制細節風險設計

    因爲具體的建造者是獨立的,所以能夠對建造過程逐步細化,而不對其餘的模塊產生任何影響

使用場景

  • 相同的方法,不一樣的執行順序,產生不一樣的事件結果時,能夠採用建造者模式。

  • 多個部件或零件,均可以裝配到一個對象中,可是產生的運行結果又不相同時,則可使用該模式。

  • 產品類很是複雜,或者產品類中的調用順序不一樣產生了不一樣的效能,這個時候使用建造者模式很是合適。

  • 在對象建立過程當中會使用到系統中的一些其餘對象,這些對象在產品對象的建立過程當中不易獲得時,也能夠採用建造者模式封裝該對象的建立過程。

    該種場景只能是一個補償方法,由於一個對象不容易得到,而在設計階段居然沒有發覺,而要經過建立者模式柔化建立過程,自己已經違反設計的最初目標。

擴展

除上面的通用源碼實現外,還有另一種更爲常見的場景,就是當一個類構造器須要傳入不少參數時,而且一般有一部分參數是可選的,若是使用構造方法建立這個類的實例,代碼可讀性會很是差,並且很容易引入錯誤,此時就能夠利用 builder模式:

public class Person {
    private final String cardId;
    private final String name;
    private final Integer age;
    private final String sex;
    private final String address;

    public static class Builder {
        // 必須的參數
        private final String cardId;
        private final String name;
        // 可選的參數
        private Integer age;
        private String sex;
        private String address;

        public Builder(String cardId, String name) {
            this.cardId = cardId;
            this.name = name;
        }

        public Builder age(Integer age) {
            this.age = age;
            return this;
        }

        public Builder sex(String sex) {
            this.sex = sex;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    private Person(Builder builder) {
        this.cardId = builder.cardId;
        this.name = builder.name;
        this.age = builder.age;
        this.sex = builder.sex;
        this.address = builder.address;
    }

    @Override
    public String toString() {
        return "cardId:" + cardId + ",name:" + name + ",age:" + age + ",sex:" + sex + ",address:" + address;
    }
}
複製代碼
public class Client {

    public static void main(String[] args) {
        Person zhangsan = new Person.Builder("100000000000000000", "張三")
                .age(28)
                .sex("MALE")
                .address("BJ")
                .build();
        System.out.println(zhangsan);

        Person lisi = new Person.Builder("100000000000000001", "李四")
                .address("TJ")
                .build();
        System.out.println(lisi);
    }
}
複製代碼

上面的代碼經過Person的內部類Builder建立一個Person實例,其中,李四對年齡和性別進行了」保密「(age和sex均爲可選參數)。能夠看到,代碼看起來更爲優雅,大大加強了可讀性,而且客戶端代碼也更容易編寫。

源碼地址:gitee.com/tianranll/j…

參考文獻:《設計模式之禪》

相關文章
相關標籤/搜索