Java設計模式--建造者模式

建造者模式【Builder Pattern 】
在模板方法模式時用到了公司生產馬車的例子。這裏繼續,客戶有了新的要求,就是能夠控制基本方法的執行順序。
先看一下類圖:

這裏寫圖片描述

定義一個車輛模型的抽象類,所有的車輛模型都繼承這個類

public abstract class CarModel {
    //這個參數是各個基本方法執行的順序
    private ArrayList<String> sequence = new ArrayList<String>();
    /*
    * 模型是啓動開始跑了
    */
    protected abstract void start();
    //能發動,那還要能停下來,那纔是真本事
    protected abstract void stop();
    //喇叭會出聲音,是滴滴叫,還是嗶嗶叫
    protected abstract void alarm();
    //引擎會轟隆隆的響,不響那是假的
    protected abstract void engineBoom();
    //那模型應該會跑吧,別管是人推的,還是電力驅動,總之要會跑
    final public void run() {
    //循環一遍,誰在前,就先執行誰
    for(int i=0;i<this.sequence.size();i++){
        String actionName = this.sequence.get(i);
        if(actionName.equalsIgnoreCase("start")){ //如果是start關鍵字,
        this.start(); //開啓汽車
        }else if(actionName.equalsIgnoreCase("stop")){ //如果是stop關鍵字
        this.stop(); //停止汽車
        }else if(actionName.equalsIgnoreCase("alarm")){ //如果是alarm關鍵字
        this.alarm(); //喇叭開始叫了
        }else if(actionName.equalsIgnoreCase("engine boom")){ //如果是engine
        boom關鍵字
        this.engineBoom(); //引擎開始轟鳴
    }
}
    //把傳遞過來的值傳遞到類內
    final public void setSequence(ArrayList<String> sequence){
        this.sequence = sequence;
    }
}

然後定義要生產的奔馳、寶馬類。

最後在主類設置執行的順序,進行調用:

    BenzModel benz = new BenzModel();
    ArrayList<String> sequence = new ArrayList<String>(); //存放run的順序
    sequence.add("engine boom"); //客戶要求,run的時候時候先發動引擎
    sequence.add("start"); //啓動起來
    sequence.add("stop"); //開了一段就停下來
    //然後我們把這個順序給奔馳車:
    benz.setSequence(sequence);
    benz.run();

其中 setSequence 方法是允許客戶自己設置一個順序,是要先跑起來在有引擎聲音還是先有引擎聲音再跑起來,還是說那個喇叭就不要響,對於一個具體的模型永遠都固定的。這樣的設計體現不出程序的擴展性。

接下來客戶可能提各種各種的需求,不同種類的車型可以有不同的執行順序,有的可以不執行。於是乎,先看一下下面的類圖設計:
這裏寫圖片描述

增加了一個 CarBuilder 的抽象類,以及兩個實現類,其目的是你要什麼排列順序的車,我就給你什麼順序的車,那我們先看 CarBuilder的定義:

public abstract class CarBuilder {
    //建造一個模型,你要給我一個順序要,就是組裝順序
    public abstract void setSequence(ArrayList<String> sequence);
    //設置完畢順序後,就可以直接拿到這個車輛模型

    public abstract CarModel getCarModel();
}

實現類可以定義如下:

public class BenzBuilder extends CarBuilder {
    private BenzModel benz = new BenzModel();

    public CarModel getCarModel() {
    return this.benz;
    }

    public void setSequence(ArrayList<String> sequence) {
    this.benz.setSequence(sequence);
    }
}

在主類中進行調用:

    ArrayList<String> sequence = new ArrayList<String>(); //存放run的順序
    sequence.add("engine boom"); //客戶要求,run的時候時候先發動引擎
    sequence.add("start"); //啓動起來
    sequence.add("stop"); //開了一段就停下來
    //要一個奔馳車:
    BenzBuilder benzBuilder = new BenzBuilder();
    //把順序給這個builder類,製造出這樣一個車出來
    benzBuilder.setSequence(sequence);
    //製造出一個奔馳車
    BenzModel benz = (BenzModel)benzBuilder.getCarModel();
    //奔馳車跑一下看看
    benz.run();

這樣便可以針對不同的車子的不同需求進行不同的設計建造。

但是如果要有不同的組合呢?類似於有一個導演指揮這演員的演出順序等。那我們設計一個導演類來擴展一下。先看類圖:

這裏寫圖片描述

增加了Director類:代碼實現

public class Director {
    private ArrayList<String> sequence = new ArrayList();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();
/*
* A類型的奔馳車模型,先start,然後stop,其他什麼引擎了,喇叭一概沒有
*/
public BenzModel getABenzModel(){
    //清理場景,這裏是一些初級程序員不注意的地方
    this.sequence.clear();
    //這隻ABenzModel的執行順序
    this.sequence.add("start");
    this.sequence.add("stop");
    //按照順序返回一個奔馳車
    this.benzBuilder.setSequence(this.sequence);
    return (BenzModel)this.benzBuilder.getCarModel();
    }
    /*
    * B型號的奔馳車模型,是先發動引擎,然後啓動,然後停止,沒有喇叭
    */
    public BenzModel getBBenzModel(){
    this.sequence.clear();
    this.sequence.add("engine boom");
    this.sequence.add("start");
    this.sequence.add("stop");
    this.benzBuilder.setSequence(this.sequence);
    return (BenzModel)this.benzBuilder.getCarModel();
    }
    ...
}

在這個導演類中就可以任意的指派方法的執行順序了

於是,在Client方法中調用只需如下:

public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        //1W輛A類型的奔馳車
        for(int i=0;i<10000;i++){
        director.getABenzModel().run();
        }
        //100W輛B類型的奔馳車
        for(int i=0;i<1000000;i++){
        director.getBBenzModel().run();
        }
        //1000W量C類型的寶馬車
        for(int i=0;i<10000000;i++){
        director.getCBMWModel().run();
        }
    }
}

對該案例的總結:
(1)CarModel 以及兩個實現類 BenzModel 和 BMWModel 叫做產品類(Product Class),這個產品類實現了模板方法模式,也就是有模板方法和基本方法。
(2)CarBuilder 以及兩個實現類 BenzBuilder 和 BMWBuilder 叫做建造者(Builder Class)。
(3)Director 類叫做導演類(Director Class),負責安排已有模塊的順序,然後告訴 Builder 開始建造
這就已經實現了建造者模式了。

總結:

四個要素
產品類:一般是一個較爲複雜的對象,也就是說創建對象的過程比較複雜,一般會有比較多的代碼量。在本類圖中,產品類是一個具體的類,而非抽象類。實際編程中,產品類可以是由一個抽象類與它的不同實現組成,也可以是由多個抽象類與他們的實現組成。
抽象建造者:引入抽象建造者的目的,是爲了將建造的具體過程交與它的子類來實現。這樣更容易擴展。一般至少會有兩個抽象方法,一個用來建造產品,一個是用來返回產品。
建造者:實現抽象類的所有未實現的方法,具體來說一般是兩項任務:組建產品;返回組建好的產品。
導演類:負責調用適當的建造者來組建產品,導演類一般不與產品類發生依賴關係,與導演類直接交互的是建造者類。一般來說,導演類被用來封裝程序中易變的部分。

注意與工廠設計模式的區別
工廠設計模式側重於生產的過程,即對象的創建,而建造者模式側重的是通過不同的執行順序,讓產品類中的調用順序不同產生了不同的效能。

使用建造者模式的好處:
1.使用建造者模式可以使客戶端不必知道產品內部組成的細節。
2.具體的建造者類之間是相互獨立的,對系統的擴展非常有利。
3.由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響。

使用建造模式的場合:

1.創建一些複雜的對象時,這些對象的內部組成構件間的建造順序是穩定的,但是對象的內部組成構件面臨着複雜的變化。
2.要創建的複雜對象的算法,獨立於該對象的組成部分,也獨立於組成部分的裝配方法時。

發佈了46 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章