設(shè)計(jì)模式-建造者模式

建造者模式:把類(lèi)對(duì)象的構(gòu)造與裝配分別實(shí)現(xiàn)。

單例、工廠、原型這幾種模式的重點(diǎn)在于創(chuàng)建出一個(gè)個(gè)的實(shí)例對(duì)象來(lái),而這個(gè)建造者模式的重點(diǎn)在于對(duì)某個(gè)對(duì)象的組成部分的裝配。

在實(shí)際開(kāi)發(fā)中,一個(gè)類(lèi)不可能只有簡(jiǎn)單的幾個(gè)屬性,往往是有大量的屬性。創(chuàng)建對(duì)象的同時(shí)或者之后,給屬性也設(shè)置好對(duì)應(yīng)的值,這個(gè)對(duì)象才有使用的價(jià)值。否則一個(gè)空對(duì)象我們用它做什么呢。

如果一個(gè)表有20個(gè)字段,那么它對(duì)應(yīng)的實(shí)體類(lèi)就有20個(gè)屬性,如何給這個(gè)類(lèi)的對(duì)象的屬性賦值呢。要么是利用構(gòu)造方法在創(chuàng)建對(duì)象的同時(shí)就賦值,要么就是創(chuàng)建一個(gè)空對(duì)象,然后用set方法給賦值。
構(gòu)造器的方法問(wèn)題就是不夠靈活,而set方法就是代碼量大。

建造者模式可以完美的解決這個(gè)問(wèn)題。
先看一下建造者模式的一般方式:
這里有三個(gè)基本角色:產(chǎn)品(有比較多、復(fù)雜的組件),構(gòu)造者,裝配者
這里以電腦這種產(chǎn)品為例:

public class Computer {

    private String cpu;
    private String memery;
    private String screen;

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", memery='" + memery + '\'' +
                ", screen='" + screen + '\'' +
                '}';
    }
    // 省略get與set方法
}

構(gòu)造者,用來(lái)模擬構(gòu)造產(chǎn)品的各個(gè)組成部分

// 抽象構(gòu)造者
public abstract class Builder {
    Computer computer = new Computer();

    // 構(gòu)建cpu
    protected abstract void buildCpu();

    // 構(gòu)建memery
    protected abstract void buildMemery();

    // 構(gòu)建screen
    protected abstract void buildScreen();

}
// 具體的建造者
public class HuaweiComputer extends Builder{
    @Override
    protected void buildCpu() {
        computer.setCpu("only amd ...");
    }

    @Override
    protected void buildMemery() {
        computer.setMemery("sangsam  1024G");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("huawei 27 big screen");
    }
}

public class AppleComputer extends Builder{
    @Override
    protected void buildCpu() {
        computer.setCpu("inter i7");
    }

    @Override
    protected void buildMemery() {
        computer.setMemery("kinston 256G");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("apple cloure");
    }
}

裝配者,不同的產(chǎn)品只是組件不同,但是裝配流程是相同的

public class Director {
    private Builder builder;

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

    public Computer createComputer(){
        builder.buildCpu();
        builder.buildMemery();
        builder.buildScreen();
        return builder.computer;
    }
}

測(cè)試

public class ClientDemo {
    public static void main(String[] args) {
        // 通過(guò)給裝配者傳遞不同的產(chǎn)品構(gòu)造者來(lái)得到不同的產(chǎn)品
//        Director director = new Director(new AppleComputer());
        Director director = new Director(new HuaweiComputer());
        Computer computer = director.createComputer();
        System.out.println(computer);
    }
}

當(dāng)然從這里我們可以看到這種模式的適用場(chǎng)景,那就是產(chǎn)品應(yīng)當(dāng)是同一類(lèi)產(chǎn)品,產(chǎn)品的組成部分可能很多,各個(gè)組成部分可能不相同,但是他們組成這個(gè)產(chǎn)品的整理邏輯(裝配流程)是相同的。

其實(shí)本質(zhì)上還是封裝,我們把不同的部分(組成部分)單獨(dú)實(shí)現(xiàn),相同的部分(裝配)統(tǒng)一實(shí)現(xiàn)。

也可以把構(gòu)造者和裝配者這兩個(gè)角色放在一起來(lái)實(shí)現(xiàn),如下:

public abstract class BuilderTotal {
    Computer computer = new Computer();
    // 構(gòu)造者:構(gòu)造產(chǎn)品的各個(gè)組成部分
    protected abstract void buildCpu();
    protected abstract void buildMemry();
    protected abstract void buildScreen();
    // 裝配者:完成組裝
    public Computer createCoumputer(){
        this.buildCpu();
        this.buildMemry();
        this.buildScreen();
        return this.computer;
    }
}

不同的產(chǎn)品

public class XiaomiComputer extends BuilderTotal{
    @Override
    protected void buildCpu() {
        computer.setCpu("xiaomi  cpu");
    }

    @Override
    protected void buildMemry() {
        computer.setMemery("xiaomi  memery");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("xiaomi screen");
    }
}

public class HpComputer extends BuilderTotal{
    @Override
    protected void buildCpu() {
        computer.setCpu("hp special cpu");
    }

    @Override
    protected void buildMemry() {
        computer.setMemery("hp special memery");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("hp special screen");
    }
}

測(cè)試:

public class ClientDemo_02 {
    public static void main(String[] args) {
        BuilderTotal hp = new HpComputer();
        Computer coumputer = hp.createCoumputer();
        System.out.println(coumputer);
        System.out.println("========================");
        BuilderTotal xiaomi = new XiaomiComputer();
        Computer computer = xiaomi.createCoumputer();
        System.out.println(computer);
    }
}

雖然這樣是把不同的功能放在同一個(gè)類(lèi)中實(shí)現(xiàn),不符合單一原則,但其實(shí)我覺(jué)得這樣的代碼可讀性要高一點(diǎn),不過(guò)當(dāng)屬性比較多的時(shí)候,也會(huì)比較亂。

接下來(lái)看一種比較巧妙的方式,利用內(nèi)部類(lèi)的方式,對(duì)產(chǎn)品的各個(gè)部分(屬性)進(jìn)行組裝,而且非常靈活。

public class Phone {
    private String brand;
    private String memory;
    private String screen;
    private String camera;
    private String clour;

    // 私有構(gòu)造方法,創(chuàng)建對(duì)象由內(nèi)部類(lèi)的方法實(shí)現(xiàn)(最后用到)
    private Phone(String brand, String memory, String screen, String camera, String clour) {
        this.brand = brand;
        this.memory = memory;
        this.screen = screen;
        this.camera = camera;
        this.clour = clour;
    }

    // 借助一個(gè)內(nèi)部類(lèi),用來(lái)構(gòu)造屬性的各個(gè)部分,并創(chuàng)建調(diào)用它的構(gòu)造方法創(chuàng)建對(duì)象返回給調(diào)用者
    public static PhoneBuilder phoneBuilder(){
        return new PhoneBuilder();
    }

    // 靜態(tài)內(nèi)部類(lèi)實(shí)現(xiàn)
    public static class PhoneBuilder{
        // 擁有和外部類(lèi)相同的參數(shù)
        private String brand;
        private String memory;
        private String screen;
        private String camera;
        private String clour;
        // 對(duì)每一個(gè)屬性提供一個(gè)方法來(lái)設(shè)置它的值,這其實(shí)就是構(gòu)造組件的部分
        public PhoneBuilder brand(String brand){
            this.brand = brand;
            // 返回自身,這樣方便使用鏈?zhǔn)骄幊?            return this;
        }
        public PhoneBuilder memory(String memory){
            this.memory = memory;
            return this;
        }
        public PhoneBuilder screen(String screen){
            this.screen = screen;
            return this;
        }
        public PhoneBuilder camera(String camera){
            this.camera = camera;
            return this;
        }
        public PhoneBuilder clour(String clour){
            this.clour = clour;
            return this;
        }
        // 最后提供一個(gè)方法,創(chuàng)建產(chǎn)品對(duì)象,參數(shù)值就是上面的方法接受到的
        public Phone build(){
            return new Phone(brand, memory, screen, camera, clour);
        }
    }

    // 只為了測(cè)試方便,忽略
    @Override
    public String toString() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", memory='" + memory + '\'' +
                ", screen='" + screen + '\'' +
                ", camera='" + camera + '\'' +
                ", clour='" + clour + '\'' +
                '}';
    }
}

只看這個(gè)類(lèi)的設(shè)計(jì)會(huì)覺(jué)得很復(fù)雜,但是使用的時(shí)候就覺(jué)得爽了:

public class PhoneClient {
    public static void main(String[] args) {
        Phone phone = Phone.phoneBuilder()      // 這一步是得到它內(nèi)部的一個(gè)構(gòu)造器
                .brand("huawei")
                .clour("black")
//                .memory("64G")
//                .camera("1000 wan")
                .screen("18 ch")
                .build();       // 這一步才是真正創(chuàng)建一個(gè)Phone對(duì)象,并使用上面接受的參數(shù)

        System.out.println(phone);
    }
}

可以看到,在得到構(gòu)造器和利用構(gòu)造器創(chuàng)建對(duì)象中間,都是設(shè)置對(duì)象的屬性值,最爽的地方就在于:隨意。想設(shè)置幾個(gè)就設(shè)置幾個(gè),而且順序隨意,而且代碼可讀性很好,很明確要給給哪些屬性設(shè)置什么值。

其實(shí)這完全就是lomboc中的注解@Builder的功能。之前只是照著別人用覺(jué)得方便,也沒(méi)有琢磨琢磨。最近學(xué)到了這個(gè),覺(jué)得這個(gè)設(shè)計(jì)真是巧妙。平時(shí)工作中只是簡(jiǎn)單的crud,動(dòng)腦筋比較少,多學(xué)學(xué)這些優(yōu)秀的東西,真的可以開(kāi)闊思路。

?著作權(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),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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