1. 程式人生 > >Java中的建造者模式

Java中的建造者模式

11.1 變化是永恆的

      又是一個週三,快要下班了,老大突然拉住我,喜滋滋地告訴我:“牛叉公司很滿意我們做的模型,又簽訂了一個合同,把賓士、寶馬的車輛模型都交給我們公司製作了,不過這次又額外增加了一個新需求:汽車的啟動、停止、喇叭聲音、引擎聲音都由客戶自己控制,他想什麼順序就什麼順序,這個沒問題吧?”

      看著老大殷切的目光,我還能說啥?非常肯定地點頭,“沒問題!”,加班加點做唄,“再苦再累就當自己二百五!再難再險就當自己二皮臉!與君共勉!”這句話說出了俺的心聲。

      那任務是接下來,又是一個時間緊,工程量大的專案,為什麼是“又”呢?因為基本上每個專案都是如此,我該怎麼來完成這個任務呢?

      首先我們分析一下需求,賓士、寶馬都是一個產品,他們有共有的屬性,牛叉公司關心的是單個模型的執行過程:賓士模型A是先有引擎聲音,然後再響喇叭;賓士模型B是先啟動起來,然後再有引擎聲音,這才是牛叉公司要關心的,那到我們老大這邊呢,就是滿足人家的要求,要什麼順序就立馬能產生什麼順序的模型出來,我就負責把老大的要求實現出來,而且還要是批量的,也就是說牛叉公司下單訂購寶馬A車模,我們老大馬上就找我“生產一個這樣的車模,啟動完畢後,喇叭響一下”,然後我們就準備開始批量生產這些模型。由我生產出N多個賓士和寶馬車輛模型,這些車輛模型的都有run()方法,但是具體到每一個模型的run()方法中間的執行任務的順序是不同的,老大說要啥順序,我就給啥順序,最終客戶買走後只能是既定的模型。好,需求還是比較複雜,我們先一個一個的解決,先從找一個最簡單的切入點——產品類,每個車都是一個產品,如圖11-1所示。

clip_image002

圖11-1 汽車模型類圖

      類圖比較簡單,在CarModel中我們定義了一個setSequence方法,車輛模型的這幾個動作要如何排布,是在這個ArrayList中定義的,然後run()方法根據sequence定義的順序完成指定的順序動作,與我們上一章節介紹的模板方法模式是不是非常類似?好,我們先看CarModel原始碼,如程式碼清單11-1所示。

程式碼清單11-1 車輛模型的抽象類

?
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263public 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")){ this.start(); //開啟汽車 }else if(actionName.equalsIgnoreCase("stop")){ this.stop(); //停止汽車 }else if(actionName.equalsIgnoreCase("alarm")){ this.alarm(); //喇叭開始叫了 }else if(actionName.equalsIgnoreCase("engine boom")){ //如果是engine boom關鍵字 this.engineBoom(); //引擎開始轟鳴 } } } //把傳遞過來的值傳遞到類內 final public void setSequence(ArrayList<String> sequence){ this.sequence = sequence; } }

CarModel的設計原理是這樣的,setSequence方法是允許客戶自己設定一個順序,是要先啟動響一下喇叭再跑起來,還是要先響一下喇叭再啟動,對於一個具體的模型永遠都固定的,但是對N多個模型就是動態的了。在子類中實現父類的基本方法,run()方法讀取sequence,然後遍歷sequence中的字串,哪個字串在先,就先執行哪個方法。

兩個實現類分別實現父類的基本方法,賓士模型如程式碼清單11-2所示。

程式碼清單11-2 賓士模型程式碼

?
123456789101112131415161718192021222324252627public class BenzModel extends CarModel { protected void alarm() { System.out.println("賓士車的喇叭聲音是這個樣子的..."); } protected void engineBoom() { System.out.println("賓士車的引擎室這個聲音的..."); } protected void start() { System.out.println("賓士車跑起來是這個樣子的..."); } protected void stop() { System.out.println("賓士車應該這樣停車..."); } }

      寶馬車模型如程式碼清單11-3所示。

程式碼清單11-3 寶馬模型程式碼

?
123456789101112131415161718192021222324252627public class BMWModel extends CarModel { protected void alarm() { System.out.println("寶馬車的喇叭聲音是這個樣子的..."); } protected void engineBoom() { System.out.println("寶馬車的引擎室這個聲音的..."); } protected void start() { System.out.println("寶馬車跑起來是這個樣子的..."); } protected void stop() { System.out.println("寶馬車應該這樣停車..."); } }

      兩個產品的實現類都完成,我們來模擬一下牛叉公司的要求:生產1件賓士模型,要求跑的時候,先發動引擎,然後再掛檔啟動,然後停下來,不需要喇叭。這個需求很容易滿足,我們增加一個場景類實現該需求,如程式碼清單11-4所示。

程式碼清單11-4 寶馬模型程式碼

?
123456789101112131415161718192021222324252627282930313233public class Client { public static void main(String[] args) { /* * 客戶告訴牛叉公司,我要這樣一個模型,然後牛叉公司就告訴我老大 * 說要這樣一個模型,這樣一個順序,然後我就來製造 */BenzModel benz = new BenzModel(); //存放run的順序 ArrayList<String> sequence = new ArrayList<String>(); sequence.add("engine boom"); //客戶要求,run的時候時候先發動引擎 sequence.add("start"); //啟動起來 sequence.add("stop"); //開了一段就停下來 //我們把這個順序賦予賓士車 benz.setSequence(sequence); benz.run(); } }

      執行結果如下所示。

賓士車的引擎是這個聲音的…

賓士車跑起來是這個樣子的…

賓士車應該這樣停車…

      看,我們組裝了這樣的一輛汽車,滿足了牛叉公司的需求了。但是想想我們的需求,汽車的動作執行順序是要能夠隨意調整的,我們只滿足了一個需求,還要下一個需求呀,然後是第2件寶馬模型,只要啟動、停止,其他的什麼都不要,第3件模型,先喇叭,然後啟動,然後停止,第4件…直到把你逼瘋為止,那怎麼辦?我們就一個一個的來寫場景類滿足嗎?不可能了,那我們要想辦法來解決這個問題,有了!我們為每種模型產品模型定義一個建造者,你要啥順序直接告訴建造者,由建造者來建造,於是乎我們就有了如圖11-2所示的類圖。

clip_image004

圖11-2 增加了建造者的汽車模型類圖

      增加了一個CarBuilder抽象類,由它來組裝各個車模,要什麼型別什麼順序的車輛模型,都由相關的子類完成,首先編寫CarBuilder程式碼,如程式碼清單11-5所示。

程式碼清單11-5 抽象汽車組裝者

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

      很簡單,每個車輛模型都要有確定的執行順序,然後才能返回一個車輛模型。賓士車的組裝者如程式碼清單11-6所示。

程式碼清單11-6 賓士車組裝者

?
1234567891011121314151617public 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); } }

      非常簡單實用的程式,給定一個汽車的執行順序,然後就返回一個賓士車,簡單了很多,寶馬車的組裝與此相同,如程式碼清單11-7所示。

程式碼清單11-7 寶馬車組裝者

?
1234567891011121314151617public class BMWBuilder extends CarBuilder { private BMWModel bmw = new BMWModel(); public CarModel getCarModel() { return this.bmw; } public void setSequence(ArrayList<String> sequence) { this.bmw.setSequence(sequence); } }

      兩個組裝者都完成了,我們再來看看牛叉公司的需求如何滿足,修改一下場景類,如程式碼清單11-8所示。

程式碼清單11-8 修改後的場景類

?
123456789101112131415161718192021222324252627282930313233343536373839public class Client { public static void main(String[] args) { /* * 客戶告訴牛叉公司,我要這樣一個模型,然後牛叉公司就告訴我老大 * 說要這樣一個模型,這樣一個順序,然後我就來製造 */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(); } }

      執行結果如下所示。

賓士車的引擎是這個聲音的…

賓士車跑起來是這個樣子的…

賓士車應該這樣停車…

      那如果我再想要個同樣順序的寶馬車呢?很簡單,再次修改一下場景類,如程式碼清單11-9所示。

程式碼清單11-9 相同順序的寶馬車的場景類

?
1234567891011121314151617181920212223242526272829303132333435363738394041public class Client { public static void main(String[] args) { 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(); //按照同樣的順序,我再要一個寶馬 BMWBuilder bmwBuilder = new BMWBuilder(); bmwBuilder.setSequence(sequence); BMWModel bmw = (BMWModel)bmwBuilder.getCarModel(); bmw.run(); } }

      執行結果如下所示。

賓士車的引擎是這個聲音的…

賓士車跑起來是這個樣子的…

賓士車應該這樣停車…

寶馬車的引擎是這個聲音的…

寶馬車跑起來是這個樣子的…

寶馬車應該這樣停車…

      看,同樣執行順序的寶馬車也生產出來了,而且程式碼是不是比剛開始直接訪問產品類(Procuct)簡單了很多。我們在做專案時,經常會有一個共識:需求是無底洞,是無理性的,不可能你告訴它不增加需求就不增加,這四個過程(start、stop、alarm、engineBoom)按照排列組合有很多種,牛叉公司可以隨意組合,它要什麼順序的車模我就必須生成什麼順序的車模,客戶可是上帝!那我們不可能預知他們要什麼順序的模型呀,怎麼辦?封裝一下,找一個導演,指揮各個事件的先後順序,然後為每種順序指定一個程式碼,你說一種我們立刻就給你生產處理,好方法,厲害!我們先修正一下類圖,如圖11-3所示。

clip_image006

圖11-3 完整汽車模型類圖

      類圖看著複雜了,但是還是比較簡單,我們增加了一個Director類,負責按照指定的順序生產模型,其中方法說明如下:

  • getABenzModel方法

      組建出A型號的賓士車輛模型,其過程為只有啟動(start)、停止(stop)方法,其他的引擎聲音、喇叭都沒有。

  • getBBenzModel方法

      組建出B型號的賓士車,其過程為先發動引擎(engine boom),然後啟動(star),再然後停車(stop),沒有喇叭。

  • getCBMWModel方法

      組建出C型號的寶馬車,其過程為先喇叭叫一下(alarm),然後(start),再然後是停車(stop),引擎不轟鳴。

  • getDBMWModel方法

      組建出D型號的寶馬車,其過程就一個啟動(start),然後一路跑到黑,永動機,沒有停止方法,沒有喇叭,沒有引擎轟鳴。

      其他的E型號、F型號……等等,可以有很多,啟動(start)、停止(stop)、喇叭(alarm)、引擎轟鳴(engine boom)這四個方法在這個類中可以隨意的自由組合,有幾種呢?好像是排列組合,這個不會算,高中數學沒學好,反正有很多種了,都可以實現。Director類如程式碼清單11-10所示。

程式碼清單11-10 導演類

?
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105public 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(); } /* * C型號的寶馬車是先按下喇叭(炫耀嘛),然後啟動,然後停止 */public BMWModel getCBMWModel(){ this.sequence.clear(); this.sequence.add("alarm"); this.sequence.add("start"); this.sequence.add("stop"); this.bmwBuilder.setSequence(this.sequence); return (BMWModel)this.bmwBuilder.getCarModel(); } /* * D型別的寶馬車只有一個功能,就是跑,啟動起來就跑,永遠不停止,牛叉 */public BMWModel getDBMWModel(){ this.sequence.clear(); this.sequence.add("start"); this.bmwBuilder.setSequence(this.sequence); return (BMWModel)this.benzBuilder.getCarModel(); } /* * 這裡還可以有很多方法,你可以先停止,然後再啟動,或者一直停著不動,靜態的嘛 * 導演類嘛,按照什麼順序是導演說了算 */}

      順便說一下,大家看一下程式中有很多this呼叫,這個我一般是這樣要求專案組成員的,如果你要呼叫類中的成員變數或方法,需要在前面加上this關鍵字,不加也能正常的跑起來,但是不清晰,加上this關鍵字,我就是要呼叫本類中成員變數或方法,而不是本方法的中的一個變數,還有super方法也是一樣,是呼叫父類的的成員變數或者方法,那就加上這個關鍵字,不要省略,這要靠約束,還有就是程式設計師的自覺性,他要是死不悔改,那咱也沒招。

      注意上面每個方法都一個this.sequence.clear(),這個估計你一看就明白,但是作為一個系統分析師或是技術經理一定要告訴告訴專案成員,ArrayList和HashMap如果定義成類的成員變數,那你在方法中呼叫一定要做一個clear的動作,防止資料混亂。如果你發生過一次類似問題的話,比如ArrayList中出現一個“出乎意料”的資料,而你又花費了幾個通宵才解決這個問題,那你會有很深刻的印象。

      有了這樣一個導演類後,我們的場景類就更容易處理了,牛叉公司要A型別的賓士車1W輛,B型別的賓士車100W輛,C型別的寶馬車1000W輛,D型別的不需要,非常容易處理,如程式碼清單11-11所示。

程式碼清單11-11 導演類

相關推薦

大話設計模式java版--建造模式

建造者模式用來解決的問題是建造的將流程與細節分開來處理的。例如:樓房的建造流程是固定的,但是具體的建造是不一定的。還有漢堡的製造流程是固定的,但是具體的用的材料和細節是不一定的,這時候建造者模式就是為了解決這個問題出現的。 建造者模式:是將一個複雜的物件的構建與它的表示分離

Android建造模式自定義Dialog

一、簡述     由於Android系統的碎片化比較嚴重,加之Android採用開源方式,世界各大OEM廠商都對自家的Android系統進行了深度定製,那麼這些原因會給我們開發者帶來一些個麻煩,比如說,我們要開發一款App就要考慮到這款App儘量在不同系統和不同OEM深度定

Java的設計模式(八):建造模式

伸縮 null clas 示例代碼 最簡 裝配 角色扮演 app 但是 介紹 今天我們將研究java中的Builder模式。Builder 設計模式是一種創造性的設計模式,如工廠模式和抽象工廠模式。 當Object包含許多屬性時,引入了Builder模式來解決Factory

NO3-java設計模式建造模式

說明 參考文獻:http://www.runoob.com/design-pattern/builder-pattern.html 上邊的這個菜鳥教程是真的不錯,我也是借花獻佛,只是自己寫了一哈,加上自己的理解和程式碼註釋來分享一下心得吧!免得以後忘了。 建造者模式的理解 建造者模式

Java設計模式(八):建造模式

介紹 今天我們將研究java中的Builder模式。Builder 設計模式是一種創造性的設計模式,如工廠模式和抽象工廠模式。 當Object包含許多屬性時,引入了Builder模式來解決Factory和Abstract Factory設計模式的一些問題。 當Object包含許多屬性時,Factory和Abs

Java建造模式

11.1 變化是永恆的       又是一個週三,快要下班了,老大突然拉住我,喜滋滋地告訴我:“牛叉公司很滿意我們做的模型,又簽訂了一個合同,把賓士、寶馬的車輛模型都交給我們公司製作了,不過這次又額外增加了一個新需求:汽車的啟動、停止、喇叭聲音、引擎聲音都由客戶自己控制,他想什麼順序就什麼順序,這個沒問題吧?

Java建造模式在專案的實際運用

建造者模式 建造者模式(Builder Pattern)是物件建立軟體設計模式,其目的是找到伸縮構造器反模式的解決方案。先簡單說一下伸縮構造器反模式是什麼:假如我們有如下建構函式: public Hero(Profession profession, Strin

Java設計模式菜鳥系列(十五)建造模式建模與實現

郵箱 system for face tom 建造者模式 data mar 方法 轉載請註明出處:http://blog.csdn.net/lhy_ycu/article/details/39863125 建造者模式(Builder):工廠類模式提供的

建造模式—設計角度重溫DNF的角色

必須 face head sta 嘟嘟 裝備 body 控制 客戶    應用場景   假設現在我們要設計DNF中的人物角色(鬼劍士、神槍手、魔法師、聖騎士、格鬥家)。然而,利用面對對象的思想,必須先從實體入手,每一個角色都包含各種裝備、武器、配飾,這些就當做要建造的零

建造模式Java與Kotlin版)

blank 客戶 arr 它的 truct rac 簡單工廠 集合 att 前文推送 設計模式 簡單工廠模式(Java與Kotlin版) 工廠方法模式(Java與Kotlin版) 抽象工廠模式(Java與Kotlin版) Kotlin基礎知識 Kotlin入門第一課

Java設計模式學習筆記,三:建造模式

() stat sys pri builder 統一 return tengine str 建造者模式:實現了構建和裝配的解耦,即對象的各個子組件單獨構建,再進行裝配,從而建造完整對象。 該模式適用於構建較為復雜的對象(多個子組件)。 不同的構建者,使用相同的裝配者,可以建

Java設計模式百例 - 建造模式

java設計模式本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/builder建造者模式(Builder Pattern)使用多個簡單的對象一步一步構建成一個復雜的對象,這種類型的設計模式屬於創建型模式。建造模式可以將一個復雜對象

Java的設計模式(七):觀察模式

name int 還要 The else 意圖 http exceptio 所有 介紹 觀察者模式是行為設計模式之一。當您對對象的狀態感興趣並希望在有任何更改時收到通知時,觀察者設計模式非常有用。在觀察者模式中,監視另一個對象狀態的對象稱為Observer,正在被監視的對象

java設計模式3.建造模式、原型模式

原型模式 情況 nbsp 寫到 指向 應用程序 模式 接口 抽象 建造者模式 一個產品常有不同的組成部分作為產品的零件,有些情況下,一個對象會有一些重要的性質,在它們沒有恰當的值之前,對象不能作為一個完整的產品使用,有些時候,一個對象的一些性質必須按照某個順序賦值才有意

Java建造模式原型和鏈式變種

建造者最開始有4個角色 1.使用者client,提出造房子 Room的需求 2.設計者,Designer,出圖紙,指揮包工頭幹,持有包工頭 3.包工頭, interface Build,擁有步驟和返回房子Room 4.Room,最終的產品 程式碼從client開始 p

Java設計模式(四)之建立型模式建造模式

一、定義: 建造者模式將一個複雜物件的構建與表示分離,使得同樣的構建過程可以建立不同的表示。 建造者模式的UML結構圖: 建造者模式主要包含四個角色:        Builder:抽象建造者。它宣告為建立一

建造模式:設計角度重溫遊戲的角色

應用場景  假設現在我們要設計DNF中的人物角色(鬼劍士、神槍手、魔法師、聖騎士、格鬥家)。然而,利用面對物件的思想,必須先從實體入手,每一個角色都包含各種裝備、武器、配飾,這些就當做要建造的零件,然後把裝備零件組裝起來,那麼就是最終人物角色的能量值,然後它就將造成不同的傷害。   回憶

JAVA設計模式之模板方法模式建造模式

一、前期回顧 上一篇《Java 設計模式之工廠方法模式與抽象工廠模式》介紹了三種工廠模式,分別是工廠方法模式,簡單工廠方法模式,抽象工廠模式,文中詳細根據實際場景介紹了三種模式的定義,實踐,最後總結了三種方式的區別,以及各個模式的適用場景。這一篇博文我們來學習下模板方法模式和建造者模式。

java設計模式精講 Debug 方式+記憶體分析 第7章 建造模式

建造者模式 7-1 建造者模式講解 7-2 建造者模式coding 7-3 建造者模式原始碼解析(jdk+guava+spring+mybatis) 7-1 建造者模式講解 7-2 建造者

java設計模式——建造模式

一. 定義與型別 定義:將一個複雜物件的構建與它的表示分離,使用同樣的構建過程可以建立不同的表示 使用者只需制定需要建造的型別就可以得到它們,建造過程以及細節不需要知道 型別:建立型 建造者模式與工廠模式比較相近,它們的區別在於, 建造者模式注重方法的呼叫順序,工廠模式注重建立產品 它們的建立力度