建造者模式

一、前言

當一個類的內(nèi)部數(shù)據(jù)過于復雜(通常是負責持有數(shù)據(jù)的類,比如Config、VO、PO、Entity...),要創(chuàng)建這個類的實例時,了解內(nèi)部結構和裝配,學習成本太高了。為方便更好的管理這個類的數(shù)據(jù),以及代碼的可讀性好,Builder模式應運而生了,Builder模式可以將一個類的構建和表示進行分離。

二、什么是建造者模式

創(chuàng)建者模式又叫建造者模式,是將一個復雜的對象的構建與它的表示分離,使
得同樣的構建過程可以創(chuàng)建不同的表示。創(chuàng)建者模式隱藏了復雜對象的創(chuàng)建過程,它把復雜對象的創(chuàng)建過程加以抽象,通過子類繼承或者重載的方式,動態(tài)的創(chuàng)建具有復合屬性的對象。

三、為什么要使用建造者模式

當一個類的構造函數(shù)參數(shù)個數(shù)超過4個,而且這些參數(shù)有些是可選的參數(shù),考慮使用構造者模式。

3.1、建造者模式解決了什么問題

當一個類的構造函數(shù)參數(shù)超過4個,而且這些參數(shù)有些是可選的時,我們通常有兩種辦法來構建它的對象。 例如我們現(xiàn)在有如下一個類計算機類Computer,其中cpu與ram是必填參數(shù),而其他3個是可選參數(shù),那么我們?nèi)绾螛嬙爝@個類的實例呢,通常有兩種常用的方式:

public class Computer {
    private String cpu;//cup 必須
    private String ram;//內(nèi)存 必須
    private int usbCount;//usb數(shù)量 可選
    private String keyboard;//鍵盤 可選
    private String display;//顯示器 可選
}

1、折疊構造函數(shù)模式(telescoping constructor pattern ),這個我們經(jīng)常用,如下代碼所示:

public class Computer {
     ...
    public Computer(String cpu, String ram) {
        this(cpu, ram, 0);
    }
    public Computer(String cpu, String ram, int usbCount) {
        this(cpu, ram, usbCount, "雙飛燕鍵盤");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard) {
        this(cpu, ram, usbCount, keyboard, "飛利浦顯示器");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
        this.cpu = cpu;
        this.ram = ram;
        this.usbCount = usbCount;
        this.keyboard = keyboard;
        this.display = display;
    }
}

2、Javabean 模式,如下所示:

public class Computer {
        ...

    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public int getUsbCount() {
        return usbCount;
    }
...
}

那么這兩種方式有什么弊端呢? 第一種主要是使用及閱讀不方便。當你要調(diào)用一個類的構造函數(shù)時,你首先要決定使用哪一個,然后里面又是一堆參數(shù),容易傳混傳錯。 第二種方式在構建過程中對象的狀態(tài)容易發(fā)生變化。因為類中的屬性是分步設置,屬性的值隨時在變化,容易造成錯誤。

四、建造者模式的結構

建造者模式結構圖.png

1、Product(產(chǎn)品角色):最終要生成的對象,例如 Computer實例。
2、Builder(抽象構造者):構建者的抽象基類(有時會使用接口代替)。其定義了構建Product的抽象步驟,其實體類需要實現(xiàn)這些步驟。其會包含一個用來返回最終產(chǎn)品的方法Product getProduct()。
3、ConcreteBuilder(具體構造者):Builder的實現(xiàn)類。
4、Director(指揮者):決定如何構建最終產(chǎn)品的算法. 其會包含一個負責組裝的方法void Construct(Builder builder), 在這個方法中通過調(diào)用builder的方法,就可以設置builder,等設置完成后,就可以通過builder的 getProduct() 方法獲得最終的產(chǎn)品。

五、簡化Builder方式代碼示例

5.1、目標產(chǎn)品和構造者

public class Computer {
    private String cpu;//cup 必須
    private String ram;//內(nèi)存 必須
    private int usbCount;//usb數(shù)量 可選
    private String keyboard;//鍵盤 可選
    private String display;//顯示器 可選
    public Computer(Builder builder) {
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }

    public static class Builder {
        private String cpu;//cup 必須
        private String ram;//內(nèi)存 必須
        private int usbCount;//usb數(shù)量 可選
        private String keyboard;//鍵盤 可選
        private String display;//顯示器 可選
        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }
        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }
        public Computer build(){
            return new Computer(this);
        }
    }
}

5.2、客戶端

public class Client {
    public static void main(String[] args){
        Computer computer=new Computer.Builder("AMD","金士頓")
                .setDisplay("飛利浦24寸")
                .setKeyboard("雙飛燕")
                .setUsbCount(3)
                .build();
    }
}

六、傳統(tǒng)Builder模式代碼示例

6.1、目標產(chǎn)品類

public class Computer {
    private String cpu;//cup 必須
    private String ram;//內(nèi)存 必須
    private int usbCount;//usb數(shù)量 可選
    private String keyboard;//鍵盤 可選
    private String display;//顯示器 可選

    public Computer(String cpu, String ram) {
        this.cpu = cpu;
        this.ram = ram;
    }
    public void setUsbCount(int usbCount) {
        this.usbCount = usbCount;
    }
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }
    public void setDisplay(String display) {
        this.display = display;
    }
}

6.2、抽象構造者類

public abstract class Builder {
    public abstract Builder usbCount (int usbCount);
    public abstract Builder keyboard (String keyboard);
    public abstract Builder display (String display);

    public abstract Computer getComputer();
}

6.3、具體構造者類

public class ComputerBuilder extends Builder {
    private Computer computer;

    public ComputerBuilder(String cpu, String ram) {
        this.computer = new Computer(cpu, ram);
    }
    @Override
    public Builder usbCount(int usbCount) {
        this.computer.setUsbCount(usbCount);
        return this;
    }
    @Override
    public Builder keyboard(String keyboard) {
        this.computer.setKeyboard(keyboard);
        return this;
    }
    @Override
    public Builder display(String display) {
        this.computer.setDisplay(display);
        return this;
    }
    @Override
    public Computer getComputer() {
        return this.computer;
    }
}

6.4、指揮者類

public class ComputerDirector {
    public Computer construct(Builder builder){
        return builder.getComputer();
    }
}

6.5、客戶端

public class Client {
    public static void main(String[] args){
        Builder builder = new ComputerBuilder("AMD", "金士頓")
                .usbCount(3)
                .keyboard("雙飛燕")
                .display("飛利浦24寸");
        ComputerDirector director = new ComputerDirector();
        Computer computer = director.construct(builder);
    }
}

七、建造者模式的優(yōu)缺點

7.1、優(yōu)點

1、客戶端不必知道產(chǎn)品內(nèi)部的組成細節(jié),將產(chǎn)品本身與產(chǎn)品的建造過程解耦,使得相同的建造過程可以建造不同的產(chǎn)品對象。
2、每個具體建筑者對象都是獨立的,與其他的具體建造者無關,因此很方便地替換具體建筑者或者增加新的具體建造者。
3、可以更加精細地控制產(chǎn)品的建造過程。將復雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,也更加方便使用程序來控制創(chuàng)建過程。

7.2、缺點

1、建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似;如果產(chǎn)品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。
2、如果產(chǎn)品的內(nèi)部變化復雜,可能會導致需要定義很多具體建造者類來實現(xiàn)這種變化,導致系統(tǒng)變得很龐大。

八、建造者和抽象工廠模式的區(qū)別

建造者模式完成的事,好像都可以通過抽象工廠模式完成,那么區(qū)別是什么?
1、與建造者模式相比,抽象工廠模式返回的是一系列相關的產(chǎn)品,這些產(chǎn)品位于不同的產(chǎn)品等級結構,構成產(chǎn)品族,而建造者模式返回的是一個組裝好的完整產(chǎn)品。抽象工廠模式更像一個汽車零件生產(chǎn)商,生產(chǎn)不同品牌汽車的各種零件。而建造者模式更像一個汽車裝配廠,通過一系列零件的組裝,最終生產(chǎn)出的是一個完整的汽車。
2、抽象工廠模式中,客戶端需實例化工廠類,然后通過工廠類獲取所需的產(chǎn)品對象。而建造者模式更側重于將復雜的構造對象的方法交給建造者去做,而客戶端只需要通過指揮者就能創(chuàng)建一個完整的產(chǎn)品實例。

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

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