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

開篇廢話

周末因懶的原因,停更了兩天。今天主要研究建造者模式。暢游各大博客網(wǎng)站,推薦一篇關(guān)于建造者模式的博客http://blog.csdn.net/self_study/article/details/51707029,簡單明了,條例清晰。如果看不懂我寫的,可以嘗試去看看別人的。。。

什么是建造者模式

講建造者模式,這里要提取幾個關(guān)鍵詞:

  • 復(fù)雜對象: 這里簡單的體現(xiàn)可以理解為,這里對象的成員數(shù)量很多,所以它很復(fù)雜。
  • 構(gòu)建過程: 對成員對象進(jìn)行賦值,業(yè)務(wù)邏輯生成等一系列使之成為一個成熟的對象。
  • 表示: 返回這個對象。
  • 構(gòu)建過程與表示分離: 一般來說,對成員對象的賦值通常在構(gòu)造函數(shù)中,這種方式除了不夠靈活之外,還有就是如果成員對象過多,因?yàn)闃?gòu)造函數(shù)就會顯得十分臃腫。所以,我們可以將構(gòu)建過程(簡單的理解為賦值,這里不嚴(yán)謹(jǐn),只是為了幫助理解概念)封裝成獨(dú)立的方法,然后再返回整個需要的實(shí)例對象。

那么建造者模式:就是為了解決生成復(fù)雜對象的問題,主要通過將構(gòu)建過程與表示分離的方法。


如何實(shí)現(xiàn)建造者模式

理解了建造者模式后,我們來實(shí)現(xiàn)它,就相對簡單了。
首先盜圖一張:


建造者模式類圖

可以看到,這里呈現(xiàn)了四個類,有時候?qū)嶋H開發(fā)中會將這個模型進(jìn)行簡化,我們這里先學(xué)習(xí)理論,因?yàn)閷?shí)際操作時,靈活變動太多了,不適合講解。但是萬變不離其宗,核心思想就是這些。

  • Product,都稱這個為產(chǎn)品類,說白了就是我需要生成的類。
  • Builder類,這是一個抽象類或者接口,用來規(guī)定構(gòu)建對象的所需方法。
  • ConcreteBuilder 對builder的抽象方法的實(shí)現(xiàn)類,通常對其優(yōu)化為product的內(nèi)部類,從而省掉builder的定義。常見的有 AlertDialog.Builder 。
  • Director 調(diào)用concrete的方法的類。一般來說,使用的建造者模式時,這個也給省了。

我們先來看一個完整版的。以造汽車為例,現(xiàn)在我們需要一輛,有四個輪子,有四個座椅,有防風(fēng)玻璃,有方向盤,發(fā)動機(jī)等等(這里只列舉這幾樣)。

  • 首先我們先看Product類,就是我們要生成的復(fù)雜對象,這里就是指小汽車。
public class Car {
    List<String> tyres = new ArrayList<>();
    List<String> carMounts = new ArrayList<>();
    String glass;
    String steeringWheel;
    String engine;

    public void setTyres(String tyres) {
        this.tyres.add(tyres);
    }

    public void setCarMounts(String carMounts) {
        this.carMounts.add(carMounts);
    }

    public void setGlass(String glass) {
        this.glass = glass;
    }

    public void setSteeringWheel(String steeringWheel) {
        this.steeringWheel = steeringWheel;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }

    public List<String> getTyres() {
        return tyres;
    }

    public List<String> getCarMounts() {
        return carMounts;
    }

    public String getGlass() {
        return glass;
    }

    public String getSteeringWheel() {
        return steeringWheel;
    }

    public String getEngine() {
        return engine;
    }

}

這里可以看到小汽車有五個屬性,然后通過setter和getter方法來對屬性賦值。

  • 然后我們先看Builder類,這是一個抽象類或者接口,具體使用看情況而定,我今天想用接口表示:
public interface Builder {
    public void buildeTyre(int wheelNumber);
    public void buildCarMounts(int carMountsNumber);
    public void buildGalss();
    public void buildSteeringWheel();
    public void buildEngine();
    public Car build();
}

這里定義了五個造小汽車零件的方法,和一個生成對象方法,因?yàn)槟悴荒苤辉爝@些零件,還需要把這些零件給組裝起來啊。

  • 緊接著我們需要ConcreteBuilder類來實(shí)現(xiàn)這些方法啊,畢竟我們是實(shí)干家,不能光說不做!concretebuilder
public class CarBuilder implements Builder {
    
    Car car = new  Car();
    @Override
    public void buildeTyre(int wheelNumber) {
        for (int i = 0; i < wheelNumber; i++) {
            car.setTyres("已經(jīng)造了" + i + "輪子了");
        }
    }

    @Override
    public void buildCarMounts(int carMountsNumber) {
        for (int i = 0; i < carMountsNumber; i++) {
            car.setCarMounts("已經(jīng)造了" + i + "椅子了");
        }
    }

    @Override
    public void buildGalss() {
        car.setGlass("防風(fēng)玻璃做好了");
    }

    @Override
    public void buildSteeringWheel() {
        car.setSteeringWheel("方向盤做好了");
    }

    @Override
    public void buildEngine() {
        car.setEngine("發(fā)動機(jī)已經(jīng)做好了");
    }

    @Override
    public Car build() {
        return car;
    }

}

這里實(shí)現(xiàn)了builder接口,沒什么好說的,值得注意的就是,在CarBuilder類中,維護(hù)了一個Car對象,實(shí)現(xiàn)的所有方法中,去調(diào)用Car的set方法,最后build()方法中去返回這個對象。
此時此刻,我們已經(jīng)能通過CarBuilder類去建造我們所需要的Car對象了。但是畢竟造汽車的工序是及其復(fù)雜了,因?yàn)槲覀冞@里只簡單的列舉了五項(xiàng),可能感覺還是比較輕松的,但是,如果有上百道工序的話,難道我們需要每次去造小車的時候都去調(diào)用這上百個方法嗎。顯然,這里構(gòu)建的過程,我們希望是不透明的,那么我們可以將這個步驟封裝起來,于是就有了Director類的出現(xiàn)。

  • 我們希望有一個技術(shù)總工來調(diào)度負(fù)責(zé)整個造車的過程。
public class AodiDirecter {
    private Builder builder;

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

    public void construct() {
        builder.buildeTyre(4);
        builder.buildCarMounts(4);
        builder.buildEngine();
        builder.buildGalss();
        builder.buildSteeringWheel();
    }
}

這樣整個建造者模式就完成了,而我們需要一個奧迪車時,只需要:

public class Buyer {
    public void buy() {
        Builder builder = new CarBuilder();
        AodiDirecter director = new AodiDirecter(builder);
        director.construct();
        Car aodiCar = builder.build();
    }
}

如果說,builder是產(chǎn)線工人們,AodiDirecter 就可以理解為奧迪工程師,工人們只知道制造器件,工程師來統(tǒng)籌設(shè)計(jì)造車的工序,安排下去后,工人們按命令執(zhí)行就行了。而對于買家來說,我并看不到你是怎么造的,反正我只要結(jié)果就行了。


但是這樣往往會很麻煩,我們通常會對其進(jìn)行精簡優(yōu)化。

看上面對建造者定義了四個功能模塊,在實(shí)現(xiàn)過程中,是不是有一些,何必多此一舉的感覺。這里我盜用了別人的代碼,工作繁忙(太懶了)還請諒解。

public class Computer {
    private String CPU;
    private String GPU;
    private String memoryType;
    private int memorySize;
    private String storageType;
    private int storageSize;
    private String screenType;
    private float screenSize;
    private String OSType;

    public static class Builder {
        // Optional parameters - initialize with default values
        private String CPU = "inter-i3";
        private String GPU = "GTX-960";
        private String memoryType = "ddr3 1666MHz";
        private int memorySize = 8;//8GB
        private String storageType = "hdd";
        private int storageSize = 1024;//1TB
        private String screenType = "IPS";
        private float screenSize = 23.8f;
        private String OSType = "Windows 10";

        public Builder() {
        }

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

        public Builder setGPU(String GPU) {
            this.GPU = GPU;
            return this;
        }
        public Builder setMemoryType(String memoryType) {
            this.memoryType = memoryType;
            return this;
        }

        public Builder setMemorySize(int memorySize) {
            this.memorySize = memorySize;
            return this;
        }
        public Builder setStorageType(String storageType) {
            this.storageType = storageType;
            return this;
        }

        public Builder setStorageSize(int storageSize) {
            this.storageSize = storageSize;
            return this;
        }

        public Builder setScreenType(String screenType) {
            this.screenType = screenType;
            return this;
        }
        public Builder setScreenSize(float screenSize) {
            this.screenSize = screenSize;
            return this;
        }

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


        public Computer create() {
            return new Computer(this);
        }

    }

    private Computer(Builder builder) {
        CPU = builder.CPU;
        GPU = builder.GPU;
        memoryType = builder.memoryType;
        memorySize = builder.memorySize;
        storageType = builder.storageType;
        storageSize = builder.storageSize;
        screenType = builder.screenType;
        screenSize = builder.screenSize;
        OSType = builder.OSType;
    }
}

可以看到,整個建造者模式就是一個類,然而這個類中存在一個靜態(tài)內(nèi)部類Builder,這個Builder,其實(shí)對應(yīng)的是建造者模式中的concreteBuilder,Computer對應(yīng)的就是我們product。去掉了Builder抽象類,因?yàn)橹苯訉?shí)現(xiàn)了。同時還缺少了Directer,因?yàn)檫@里的設(shè)計(jì)是暴露構(gòu)建細(xì)節(jié),所以就不需要了。
這種方式的好處就是,過程可控。我們來看看調(diào)用。

Computer computer = new Computer.Builder()
        .setCPU("inter-skylake-i7")
        .setGPU("GTX-Titan")
        .setMemoryType("ddr4-2133MHz")
        .setMemorySize(16)
        .setStorageType("ssd")
        .setStorageSize(512)
        .setScreenType("IPS")
        .setScreenSize(28)
        .setOSType("Ubuntu/Window10")
        .create();

這是一種鏈?zhǔn)秸{(diào)用,也是我們常見的建造者模式。我們可以對每個成員對象進(jìn)行控制,從而得到我們想要的product。當(dāng)然,我們看回Computer類的實(shí)現(xiàn),發(fā)現(xiàn),每個成員對象都是有個默認(rèn)值的。也就是說,你完全可以通過new Computer.Builder().create()來獲取默認(rèn)的實(shí)例對象,這基本就是Directer的功能。所以精簡下來,發(fā)現(xiàn)建造者模式還是挺實(shí)用的。
然而在大型的系統(tǒng)中,精簡版的建造者模式,并不是很適用,因?yàn)樗尼槍π蕴珡?qiáng),往往呈現(xiàn)出來的是同一種產(chǎn)品,拓展性并不是很好,而我們使用原始版的話,可以對Directer進(jìn)行拓展,可以更加多元靈活。

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

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

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