天天看點

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

版權聲明:尊重部落客原創文章,轉載請注明出處哦~http://blog.csdn.net/eson_15/article/details/51325765

        假如現在要生産兩種車,奔馳和寶馬,這兩輛車都有共性,我們所需要關注的是單個車的運作過程,這才是老闆所關心的點所在。我們先這樣想,針對這個需求,我們要找到一個切入點,那就是産品類,每個車都是一個産品,那麼在産品類中我們可以控制車的運作順序,這樣每個車都可以擁有自己想要的順序了。基于此,我們設計如下類圖:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

         我們看到carmodel中有個setsequence方法,通過傳入一個arraylist來控制運作順序,run方法根據這個arraylist中儲存的順序執行,然後奔馳車和寶馬車分别繼承這個carmodel即可,這貌似是很好的實作,它很像上一節的模闆方法模式,隻是多了個方法可以設定運作順序。我們看一下carmodel具體代碼的實作:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public abstract class carmodel {  

    private arraylist<string> sequence = new arraylist<string>(); //維護一個arraylist儲存執行指令關鍵字  

    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 ++) { //根據arraylist中儲存的順序執行相應的動作  

            string actionname = this.sequence.get(i);  

            if(actionname.equalsignorecase("start")) {  

                this.start(); //啟動汽車  

            } else if(actionname.equalsignorecase("stop")) {  

                this.stop(); //停止汽車  

            } else if(actionname.equalsignorecase("alarm")) {  

                this.alarm(); //汽車鳴笛  

            } else if(actionname.equalsignorecase("engine boom")) {  

                this.engineboom(); //汽車轟鳴  

            }  

        }  

    }  

    final public void setsequence(arraylist<string> sequence) { //獲得執行順序的指令,即一個arraylist  

        this.sequence = sequence;  

}  

        carmodel中的setsequence方法允許客戶自己設定一個順序,我們看看子類的實作:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public class benzmodel extends carmodel {  

    @override  

    protected void start() {  

        system.out.println("奔馳啟動……");  

    protected void stop() {  

        system.out.println("奔馳停止……");  

    protected void alarm() {  

        system.out.println("奔馳鳴笛……");  

    protected void engineboom() {  

        system.out.println("奔馳轟鳴");  

//寶馬就略了……一樣的  

        下面我們增加一個測試類實作該需求:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public class client {  

    public static void main(string[] args) {  

        benzmodel benz = new benzmodel();  

        //存放run順序  

        arraylist<string> sequence = new arraylist<string>();  

        sequence.add("engine boom"); //老闆說:跑之前先轟鳴比較帥!  

        sequence.add("start");  

        sequence.add("stop");  

        //我們把這個順序賦予奔馳  

        benz.setsequence(sequence);  

        benz.run();  

        這樣好像已經順利完成了任務了,但是别忘了,我們這隻是滿足了一個需求,如果下一個需求是寶馬車隻轟鳴,再下一個需求是奔馳車隻跑不停……等等……那豈不是要一個個寫測試類來實作?顯然這不是我們想要的。

        我們可以這樣做:為每種産品模型定義一個建造者,你要啥順序直接告訴建造者,由建造者來建造即可,于是我們重新設計類圖:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

        我們增加了一個carbuilder類,由它來組裝各個車模型,要什麼類型的順序就由相關的子類去完成即可,我們來看看carbuilder的代碼:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public abstract class carbuilder {  

    //建造一個模型,你要給我一個順序要求  

    public abstract void setsequence(arraylist<string> sequence);  

    //設定完畢順序後,就可以直接拿到這個車輛模型了  

    public abstract carmodel getcarmodel();  

        很簡單,每個車輛模型都要有确定的運作順序,然後才能傳回一個車輛模型,奔馳車和寶馬車組裝者的代碼如下:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public class benzbuilder extends carbuilder {  

    private benzmodel benz = new benzmodel(); //奔馳車模型  

    public void setsequence(arraylist<string> sequence) {  

        this.benz.setsequence(sequence); //設定奔馳車模型的運作順序  

    public carmodel getcarmodel() {  

        return this.benz; //将這個模型傳回  

//寶馬車一樣,不寫了……  

        現在兩輛車的組裝者都寫好了,現在我們寫一個測試類來測試一下:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

        sequence.add("engine boom");  

        //要用這個順序造一輛奔馳  

        benzbuilder benzbuilder = new benzbuilder();  

        //把順序給奔馳組裝者  

        benzbuilder.setsequence(sequence);  

        //奔馳組裝者拿到順序後就給你生産一輛來  

        benzmodel benz = (benzmodel) benzbuilder.getcarmodel();  

       如果我要生産一輛寶馬車,隻需要換成寶馬車的組裝者即可,這樣我們不用直接通路産品類了,全部通路組裝者就行,是不是感覺到很友善,我管你怎麼生産,我扔給你個順序,你給我弄輛車出來,要的就是這種效果!

        可是人的需求是個無底洞,特别是老闆,他哪天不爽了,又要換順序,這樣還是挺麻煩的,四個過程(start、stop、alarm、engine boom)按排列組合也有很多中情況,我們不能保證老闆想要哪種順序,咋整?無奈,我們隻能使出最後的殺手锏了,找個設計師過來指揮各個時間的先後順序,然後為每種順序指定一個代碼,你說一種我們立刻就給你生産!我們再修改一下類圖……

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

        類圖看着有點複雜,其實不然,隻是在原來的基礎上增加了一個director類充當着設計師的角色,負責按照指定的順序生産模型,比如我們要一個a順序的奔馳車,b順序的奔馳車,a順序的寶馬車,b順序的寶馬車……等等,我們來看下director類的代碼:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

public class director {  

    private arraylist<string> sequence = new arraylist<string>();  

    private benzbuilder benzbuilder = new benzbuilder();  

    private bwmbuilder bwmbuilder = new bwmbuilder();  

    //a順序的奔馳車  

    public benzmodel getabenzmodel() {  

        this.sequence.clear();  

        this.sequence.add("start");  

        this.sequence.add("stop");  

        //傳回a順序的奔馳車  

        this.benzbuilder.setsequence(sequence);  

        return (benzmodel) this.benzbuilder.getcarmodel();  

    //b順序的奔馳車  

    public benzmodel getbbenzmodel() {  

        this.sequence.add("engine boom");  

        //傳回b順序的奔馳車  

    //c順序的寶馬車  

    public benzmodel getcbwmmodel() {  

        this.sequence.add("alarm");  

        //傳回c順序的寶馬車  

        this.bwmbuilder.setsequence(sequence);  

        return (benzmodel) this.bwmbuilder.getcarmodel();  

    //d順序的寶馬車  

    public benzmodel getdbwmmodel() {  

        //傳回d順序的寶馬車  

    //還有很多其他需求,設計師嘛,想啥需求就給你弄啥需求  

        有了這樣一個設計師,我們的測試類就更容易處理了,比如現在老闆要10000輛a類奔馳車,100000輛b類奔馳車,20000c類型寶馬車,d類型不要:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

        director director = new director();  

        for(int i = 0; i < 10000; i ++) {  

            director.getabenzmodel();  

        for(int i = 0; i < 100000; i ++) {  

            director.getbbenzmodel();  

        for(int i = 0; i < 20000; i ++) {  

            director.getcbwmmodel();  

        是不是很清晰很簡單,我們重構代碼的最終第就是簡單清晰。這就是建造者模式。

        我們來看看建造者模式的一般定義:separate the construction of a complex object from its representation so that the same construction process can create different representations. 即:将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。比如上面的例子,我們可以用同樣的順序構造不同的車。建造者模式的通用類圖如下:

【java設計模式】之 建造者(Builder)模式 1. 汽車無休止的改造 2. 建造者模式的定義 3. 建造者模式的優點 4. 建造者模式的使用場景

        product是最終的産品類,builder是建造者,director是指揮者。director負責安排已有子產品的順序,然後告訴builder開始建造。

        1)封裝性:使用建造者模式可以是用戶端不必知道産品内部組成的細節。

        2)建造者獨立,容易擴充:benzbuilder和bmwbuilder是互相獨立的,對系統擴充非常有利。

        3)便于控制細節風險:由于具體的建造者是獨立的,是以可以對建造者過程逐漸細化,而不對其他的子產品産生任何影響。

        1)相同的方法,不同的執行順序,産生不同的事件結果時,可以使用建造者模式。

        2)多個部件或零件,都可以裝配到一個對象中,但是産生的運作結果又不想同時,可以使用建造者模式。

        3)産品類非常複雜,或者産品類中的調用順序不同産生了不同的效能,這時候可以使用建造者模式。

        4)在對象建立過程中會使用到系統的一些其他對象,這些對象在産品對象的建立過程中不易得到,也可以采用建造者模式封裝該對象的建立過程。這種場景隻能是一個補償的方法,因為一個對象不容易獲得,而在設計階段竟然沒有發現,而要通過設計這模式來柔化建立過程,本身設計已經出問題了。

        到這裡,我們會發現,建造者模式和工廠方法模式有點像。但是兩者有差別:建造者模式關注的是零件類型和裝配工藝(順序),而工廠模式是建立一個對象,這是最大不同的地方。

        建立者模式就介紹這麼多吧,如有錯誤之處,歡迎留言指正~

_____________________________________________________________________________________________________________________________________________________

-----樂于分享,共同進步!