建造者模式(Builder Pattern)

一、什么是建造者模式

建造者模式是將一個(gè)復(fù)雜的對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

建造者模式屬于創(chuàng)建型模式,對(duì)使用者而言,只需要指定需要建造的類型就可以獲得對(duì)象,建造過程和細(xì)節(jié)不需要了解。在實(shí)際的開發(fā)過程中,使用 Builder Pattern 來替代多參數(shù)構(gòu)造函數(shù)是一個(gè)比較好的實(shí)踐法則。

建造者模式的概念聽上去有點(diǎn)抽象,但是實(shí)際上可以這么說,基本上大家都用過,只是可能自己不知道這就是建造者模式而已。

二、建造者模式角色

1??產(chǎn)品(Product):要?jiǎng)?chuàng)建的產(chǎn)品對(duì)象。

public class Product {

    private String name;
    private Integer val;

    Product(String name, Integer val) {
        this.name = name;
        this.val = val;
    }
    @Override
    public String toString() {
        return "Product is " + name + " value is " + val;
    }
}

2??抽象建造者(Builder):建造者的抽象類,規(guī)范產(chǎn)品對(duì)象的各個(gè)組成部分的建造,一般由子類實(shí)現(xiàn)具體建造過程。

public abstract class Builder {

    protected Integer val;
    protected String name;

    // 設(shè)置產(chǎn)品不同部分,以獲得不同的產(chǎn)品
    public abstract void setVal(Integer val);
    // 設(shè)置名字 公用方法
    public void setName(String name) {
        this.name = name;
    }
    // 建造產(chǎn)品
    public abstract Product buildProduct();
}

3??具體建造者(ConcreteBuilder):具體的 Builder 類,根據(jù)不同的業(yè)務(wù)邏輯,具體到各個(gè)對(duì)象的各個(gè)組成部分的建造。

public class ConcreteBuilder extends Builder {

    @Override
    public void setVal(Integer val) {
        this.val = val + 100;
    }
    @Override
    // 組建一個(gè)產(chǎn)品
    public Product buildProduct() {
        // 此處還可以寫特殊的校驗(yàn)邏輯
        return new Product(name, val);
    }
}

4??調(diào)用者(Director):調(diào)用具體的建造者來創(chuàng)建各個(gè)對(duì)象的各個(gè)部分。

public class Director {
    private Builder builder = new ConcreteBuilder();
    public Product getAProduct() {
        // 設(shè)置不同的零件,產(chǎn)生不同的產(chǎn)品
        builder.setName("ProductA");
        builder.setVal(2);
        return builder.buildProduct();
    }
}

三、示例

在設(shè)計(jì)模式中對(duì) Builder Pattern 的定義是用于構(gòu)建復(fù)雜對(duì)象的一種模式,所構(gòu)建的對(duì)象往往需要多步初始化或賦值才能完成。在實(shí)際的開發(fā)過程中,使用 Builder Pattern 來替代多參數(shù)構(gòu)造函數(shù)是一個(gè)比較好的實(shí)踐法則。

常常遇到編寫一個(gè)這樣的實(shí)現(xiàn)類,這個(gè)類擁有多個(gè)構(gòu)造函數(shù):

DoContact(String name);
DoContact(String name, int age);
DoContact(String name, int age, String address);
DoContact(String name, int age, String address, int cardID);

這樣一系列的構(gòu)造函數(shù)主要目的就是為了提供給客戶更多的調(diào)用選擇,以處理不同的構(gòu)造請(qǐng)求。這種方法很常見,很有效力,但缺點(diǎn)也很多:
1??類的作者不得不書寫多種參數(shù)組合的構(gòu)造函數(shù),而且其中還需要設(shè)置默認(rèn)參數(shù)值,這是一個(gè)細(xì)心而又枯燥的工作。
2??其次,這樣的構(gòu)造函數(shù)靈活性也不高,而且在調(diào)用時(shí)不得不提供一些沒有意義的參數(shù)值,例如,DoDoContact("Ace", -1, "SH"),顯然年齡為負(fù)數(shù)沒有意義,但是又不得不這樣做,以符合 Java 的規(guī)范。如果這樣的代碼發(fā)布后,后面的維護(hù)者就會(huì)很頭痛,因?yàn)楦静恢肋@個(gè) -1 是什么含義。

對(duì)于這樣的情況,就非常適合使用 Builder Pattern。Builder Pattern的要點(diǎn)就是通過一個(gè)代理來完成對(duì)象的構(gòu)建過程。這個(gè)代理職責(zé)就是完成構(gòu)建的各個(gè)步驟,同時(shí)它也是易擴(kuò)展的。下面是改寫自 Effective Java 里面的一段代碼:

public class DoContact {
    private final int age;
    private final int safeID;
    private final String name;
    private final String address;

    public int getAge() {
        return age;
    }
    public int getSafeID() {
        return safeID;
    }
    public String getName() {
        return name;
    }
    public String getAddress() {
        return address;
    }

    public static class Builder {
        private int age = 0;
        private int safeID = 0;
        private String name = null;
        private String address = null;

        // 構(gòu)建的步驟
        public Builder(String name) {
            this.name = name;
        }
        public Builder age(int val) {
            this.age = val;
            return this;
        }
        public Builder safeID(int val) {
            this.safeID = val;
            return this;
        }
        public Builder address(String val) {
            this.address = val;
            return this;
        }
        // 構(gòu)建,返回一個(gè)新對(duì)象
        public DoContact build() {
            return new DoContact(this);
        }
    }

    private DoContact(Builder b) {
        age = b.age;
        safeID = b.safeID;
        name = b.name;
        address = b.address;
    }
}

最終,調(diào)用者可以很靈活的去構(gòu)建這個(gè)對(duì)象:

public class kfd {
    public static void main(String[] args) {
        DoContact object = new DoContact.Builder("MChopin").age(18)
                .address("shanghai").build();
        System.out.println("name=" + object.getName() + " age=" + object.getAge()
                + " address=" + object.getAddress());
    }
}

四、建造者模式優(yōu)缺點(diǎn)

1??優(yōu)點(diǎn)

  1. 封裝性好,創(chuàng)建和使用分離
  2. 擴(kuò)展性好,建造類之間獨(dú)立,一定程度上實(shí)現(xiàn)了解耦

2??缺點(diǎn)

  1. 產(chǎn)生多余的 Builder 對(duì)象
  2. 產(chǎn)品內(nèi)部發(fā)生變化時(shí),建造者都需要修改,成本較大

五、建造者模式和工廠模式區(qū)別

建造者模式優(yōu)點(diǎn)類似于工廠模式,都是用來創(chuàng)建一個(gè)對(duì)象,但是有很大的區(qū)別,主要區(qū)別如下:

1??建造者模式更加注重方法的調(diào)用順序,工廠模式注重于創(chuàng)建完整對(duì)象。
2??建造者模式根據(jù)不同的產(chǎn)品零件和順序可以創(chuàng)造出不同的產(chǎn)品,而工廠模式創(chuàng)建出來的產(chǎn)品都是一樣的。
3??建造者模式使用者需要知道這個(gè)產(chǎn)品有哪些零件組成,而工廠模式的使用者不需要知道,直接創(chuàng)建就行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容