設(shè)計模式詳解之建造者模式

建造者模式屬于創(chuàng)建型模式,提供了一種創(chuàng)建對象的最佳方式。

定義:將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

主要作用:在用戶不知道對象的建造過程和細(xì)節(jié)的情況下就可以直接創(chuàng)建復(fù)雜的對象。

建造者模式的四個對象

Product產(chǎn)品類:

通常是實現(xiàn)了模板方法模式(這里可以后續(xù)看我的更新博客,如果我更新了),也就是有模板方法和基本方法。

Builder抽象建造者:

規(guī)范產(chǎn)品的組建,一般是由子類實現(xiàn)。

ConcreteBuilder具體建造者:

實現(xiàn)抽象類定義的所有方法,并且返回一個組建好的對象。

Director導(dǎo)演類:

負(fù)責(zé)安排已有模塊的順序,然后告訴Builder開始建造。

例子

舉個例子:

  • 工廠(建造者模式):負(fù)責(zé)制造汽車(組裝過程和細(xì)節(jié)在工廠內(nèi))
  • 汽車購買者(用戶):你只要說出你需要的型號(對象的類型和內(nèi)容),然后直接購買就可以使用了(不需要知道汽車是怎么組裝的(比如車輪,車門,發(fā)動機,方向盤等等))

同樣的,我們以這個例子用代碼來實現(xiàn)一下更能清晰的了解。

我們的汽車類(Car),也就是我們的產(chǎn)品

package builder;

public abstract class Builder {
    private String wheel;  //車輪
    private String carDoor; //車門
    private String engine;  //發(fā)動機
    private String steeringWheel;  //方向盤

    ...我們的get和set方法(為了簡潔,我就不展示了)...

    @Override
    public String toString() {
        return "Builder{" +
                "wheel='" + wheel + '\'' +
                ", carDoor='" + carDoor + '\'' +
                ", engine='" + engine + '\'' +
                ", steeringWheel='" + steeringWheel + '\'' +
                '}';
    }
}

我們的建造抽象類(Builder

package builder;

public abstract class Builder {

    abstract void buildWheel(); //建造車輪
    abstract void buildCarDoor(); //建造車門
    abstract void buildEngine(); //建造發(fā)動機
    abstract void buildSteeringWheel(); //建造方向盤

    //建造完成,獲得車輛
    abstract Car getCar();
}

我們的建造實現(xiàn)類(ConcreteBuilder

package builder;

public class ConcreteBuilder extends Builder{

    private Car car;

    //定義一個空構(gòu)造方法,在實例化的同時實例我們的車
    public ConcreteBuilder(){
        car = new Car();
    }

    @Override
    void buildWheel() {
        car.setWheel("輪子");
    }

    @Override
    void buildCarDoor() {
        car.setCarDoor("車門");
    }

    @Override
    void buildEngine() {
        car.setEngine("發(fā)動機");
    }

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

    @Override
    Car getCar() {
        return car;
    }
}

我們的導(dǎo)演類(Director),用來指揮我們的創(chuàng)建過程,比如創(chuàng)建順序

package builder;

public class Director {

    public Car carBuilder(Builder builder){
        //按照我們的導(dǎo)演的順序來創(chuàng)建車輛
        builder.buildWheel();
        builder.buildCarDoor();
        builder.buildEngine();
        builder.buildSteeringWheel();
        
        //創(chuàng)建完之后,返回我們創(chuàng)建完的車輛
        return builder.getCar();
    }

}

我們在測試類中測試一下

package builder;

public class Test {

    public static void main(String[] args) {

        //創(chuàng)建一個我們的導(dǎo)演,指揮
        Director director = new Director();
        //導(dǎo)演指揮我們具體的實現(xiàn)類去創(chuàng)建車輛
        Car car = director.carBuilder(new ConcreteBuilder());
        System.out.println(car.toString());
    }

}


//測試結(jié)果
Car{wheel='輪子', carDoor='車門', engine='發(fā)動機', steeringWheel='方向盤'}
Process finished with exit code 0

可以看到,通過這樣的建造者模式,我們的復(fù)雜過程被我們封裝了起來。但是我們也發(fā)現(xiàn)了我們的導(dǎo)演可以指揮順序,但是里面具體的參數(shù),比如想建造什么無法修改。其實也可以,我們對導(dǎo)演類進(jìn)行擴展一下就行。

我們通過靜態(tài)內(nèi)部類實現(xiàn)零件無序裝配構(gòu)造,這種方式使用更加靈活,更符合定義。使用的時候可以根據(jù)用戶需求自定義更改內(nèi)容。我們對其修改后,示例代碼如下:

我們對抽象建造的抽象方法添加了傳遞參數(shù),修改了返回類型

package builder;

public abstract class Builder {

    abstract Builder buildWheel(String msg); //建造車輪
    abstract Builder buildCarDoor(String msg); //建造車門
    abstract Builder buildEngine(String msg); //建造發(fā)動機
    abstract Builder buildSteeringWheel(String msg); //建造方向盤

    //建造完成,獲得車輛
    abstract Car getCar();
}

然后在實現(xiàn)類進(jìn)行實現(xiàn)

package builder;

public class ConcreteBuilder extends Builder{

    private Car car;

    //定義一個空構(gòu)造方法,在實例化的同時實例我們的車
    public ConcreteBuilder(){
        car = new Car();
    }

    @Override
    Builder buildWheel(String msg) {
        car.setWheel(msg);
        return this;
    }

    @Override
    Builder buildCarDoor(String msg) {
        car.setCarDoor(msg);
        return this;
    }

    @Override
    Builder buildEngine(String msg) {
        car.setEngine(msg);
        return this;
    }

    @Override
    Builder buildSteeringWheel(String msg) {
        car.setSteeringWheel(msg);
        return this;
    }

    @Override
    Car getCar() {
        return car;
    }
}

這時我們在導(dǎo)演類里面,就可以自由的傳遞我們需要的參數(shù)來建造車輛,也可以指定順序。

package builder;

public class Director {

    public Car carBuilder(Builder builder){
        //創(chuàng)建自定義車輛,自定義建造順序
        return builder.buildWheel("厲害的車輪")
                .buildCarDoor("漂亮的車門")
                .buildEngine("馬力十足的引擎")
                .buildSteeringWheel("舒服的方向盤")
                .getCar();
    }

}

測試類的測試結(jié)果

Car{wheel='厲害的車輪', carDoor='漂亮的車門', engine='馬力十足的引擎', steeringWheel='舒服的方向盤'}

Process finished with exit code 0

總結(jié)

建造者模式關(guān)注的是零件類型和裝配順序,我們可以總結(jié)一下它的優(yōu)缺點和使用場景。

優(yōu)點:

  • 封裝性:產(chǎn)品的建造和表示分離,實現(xiàn)了解耦。使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)。
  • 建造者獨立,容易擴展:具體的建造者之間是相互獨立的,這有利于系統(tǒng)的擴展,增加新的具體建造者無需修改原有類庫的代碼,符合”符合開閉原則“。
  • 便于控制細(xì)節(jié)風(fēng)險:由于具體的建造者是獨立的,因此可以對建造過程逐步細(xì)化,而不對其他的模塊產(chǎn)生任何影響。

缺點:

  • 建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似;如果產(chǎn)品之間

差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。

  • 如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會導(dǎo)致需要定義很多具體建造者類來實現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大。

使用場景:

  • 需要生成的產(chǎn)品對象有復(fù)雜的內(nèi)部結(jié)構(gòu),這些產(chǎn)品對象具備共性
  • 隔離復(fù)雜對象的創(chuàng)建和使用,并使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品
  • 適合于一個具有較多的零件(屬性)的產(chǎn)品(對象)的創(chuàng)建過程

補充:

通過學(xué)習(xí)建造者模式,我們可以發(fā)現(xiàn)這與我們的抽象工廠模式很是相像,但是也是有不同的地方。(關(guān)于工廠模式可以看我的設(shè)計模式詳解之工廠模式

  • 與抽象工廠相比,建造者模式返回一個組裝好的完整產(chǎn)品,而抽象工廠模式返回一系列相關(guān)的產(chǎn)品,這些產(chǎn)品位于不同的產(chǎn)品等級結(jié)構(gòu),構(gòu)成了一個產(chǎn)品族。
  • 在抽象工廠模式中,客戶端示例工廠類,然后調(diào)用工廠方法獲取所需產(chǎn)品對象,而在建造者模式中,客戶端不可以直接調(diào)用建造者的相關(guān)方法,而是通過導(dǎo)演類來指導(dǎo)如何生成對象,包括對象的組裝過程和建造順序,它側(cè)重于一步步構(gòu)造一個復(fù)雜對象,返回一個完整的對象。
  • 如果將抽象工廠看成汽車配件生產(chǎn)工廠,生產(chǎn)一個產(chǎn)品族的的產(chǎn)品,那么建造者模式就是一個汽車組裝工廠,通過對部件組裝可以返回一輛完整的汽車。

建造者模式最主要的功能是基本方法的調(diào)用順序安排,因為組裝順序不同對象效能也不同,這才是建造者模式要表達(dá)的核心意義。

參考資料

(書籍)大話設(shè)計模式

(視頻)遇見狂神說:通俗易懂的23種設(shè)計模式教學(xué)

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

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