设计模式-建造者模式(转自:http://www.cnblogs.com/cbf4life/archive/2010/01/14/1647710.html)...
11.1 變化是永恒的
????? 又是一個周三,快要下班了,老大突然拉住我,喜滋滋地告訴我:“牛叉公司很滿意我們做的模型,又簽訂了一個合同,把奔馳、寶馬的車輛模型都交給我們公司制作了,不過這次又額外增加了一個新需求:汽車的啟動、停止、喇叭聲音、引擎聲音都由客戶自己控制,他想什么順序就什么順序,這個沒問題吧?”
????? 看著老大殷切的目光,我還能說啥?非常肯定地點頭,“沒問題!”,加班加點做唄,“再苦再累就當自己二百五!再難再險就當自己二皮臉!與君共勉!”這句話說出了俺的心聲。
????? 那任務是接下來,又是一個時間緊,工程量大的項目,為什么是“又”呢?因為基本上每個項目都是如此,我該怎么來完成這個任務呢?
????? 首先我們分析一下需求,奔馳、寶馬都是一個產品,他們有共有的屬性,牛叉公司關心的是單個模型的運行過程:奔馳模型A是先有引擎聲音,然后再響喇叭;奔馳模型B是先啟動起來,然后再有引擎聲音,這才是牛叉公司要關心的,那到我們老大這邊呢,就是滿足人家的要求,要什么順序就立馬能產生什么順序的模型出來,我就負責把老大的要求實現出來,而且還要是批量的,也就是說牛叉公司下單訂購寶馬A車模,我們老大馬上就找我“生產一個這樣的車模,啟動完畢后,喇叭響一下”,然后我們就準備開始批量生產這些模型。由我生產出N多個奔馳和寶馬車輛模型,這些車輛模型的都有run()方法,但是具體到每一個模型的run()方法中間的執行任務的順序是不同的,老大說要啥順序,我就給啥順序,最終客戶買走后只能是既定的模型。好,需求還是比較復雜,我們先一個一個的解決,先從找一個最簡單的切入點——產品類,每個車都是一個產品,如圖11-1所示。
圖11-1 汽車模型類圖
????? 類圖比較簡單,在CarModel中我們定義了一個setSequence方法,車輛模型的這幾個動作要如何排布,是在這個ArrayList中定義的,然后run()方法根據sequence定義的順序完成指定的順序動作,與我們上一章節介紹的模板方法模式是不是非常類似?好,我們先看CarModel源代碼,如代碼清單11-1所示。
代碼清單11-1 車輛模型的抽象類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | 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")){ 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 奔馳模型代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public?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 寶馬模型代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public?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 寶馬模型代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public?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所示的類圖。
圖11-2 增加了建造者的汽車模型類圖
????? 增加了一個CarBuilder抽象類,由它來組裝各個車模,要什么類型什么順序的車輛模型,都由相關的子類完成,首先編寫CarBuilder代碼,如代碼清單11-5所示。
代碼清單11-5 抽象汽車組裝者
| 1 2 3 4 5 6 7 8 9 10 11 | public?abstract?class?CarBuilder { //建造一個模型,你要給我一個順序要,就是組裝順序 public?abstract?void?setSequence(ArrayList<String> sequence); //設置完畢順序后,就可以直接拿到這個車輛模型 public?abstract?CarModel getCarModel(); } |
????? 很簡單,每個車輛模型都要有確定的運行順序,然后才能返回一個車輛模型。奔馳車的組裝者如代碼清單11-6所示。
代碼清單11-6 奔馳車組裝者
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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); } } |
????? 非常簡單實用的程序,給定一個汽車的運行順序,然后就返回一個奔馳車,簡單了很多,寶馬車的組裝與此相同,如代碼清單11-7所示。
代碼清單11-7 寶馬車組裝者
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public?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 修改后的場景類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public?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 相同順序的寶馬車的場景類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public?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所示。
圖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 導演類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 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(); } /* * 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 導演類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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(); } } } |
????? 清晰,簡單吧,我們寫程序重構的最終目的就是:簡單、清晰,代碼是讓人看的,不是寫完就完事了,我一直在教育我帶的團隊,Java程序不是像我們前輩寫二進制代碼、匯編一樣,寫完基本上就自己能看懂,別人看就跟看天書一樣,現在的高級語言,要像寫中文漢字一樣,你寫的,別人能看懂。——這就是建造者模式。
11.2 建造者模式的定義
????? 建造者模式(Builder Pattern)也叫做生成器模式,其定義如下:
??????Separate the construction of a complex object from its representation so that the same construction process can create different representations.?將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
????? 建造者模式的通用類圖如圖11-4所示。
圖11-4 建造者模式通用類圖
????? 在建造者模式中,有如下四個角色:
- Product 產品類
????? 通常是實現了模板方法模式,也就是有模板方法和基本方法,這個參考上一章節的模板方法模式。在例子中,BenzModel和BMWModel就屬于產品類。
- Builder 抽象建造者
????? 規范產品的組建,一般是由子類實現。在例子中,CarBuilder屬于抽象建造者。
- ConcreteBuilder 具體建造者
????? 實現抽象類定義的所有方法,并且返回一個組件好的對象。在例子中,BenzBuilder和BMWBuilder就屬于具體建造者。
- Director 導演
????? 負責安排已有模塊的順序,然后告訴Builder開始建造,在上面的例子中就是我們的老大,牛叉公司找到老大,說我要這個,這個,那個類型的車輛模型,然后老大就把命令傳遞給我,我和我的團隊就開始拼命的建造,于是一個項目建設完畢了。
????? 建造者模式的通用源代碼也比較簡單,先看Product類,通常它是一個組合或繼承(如模板方法模式)產生的類,如代碼清單11-12所示。
代碼清單11-12 產品類
| 1 2 3 4 5 6 7 8 9 | public?class?Product { public?void?doSomething(){ //獨立業務處理 } } |
????? 抽象建造者如代碼清單11-13所示。
代碼清單11-13 抽象建造者
| 1 2 3 4 5 6 7 8 9 10 11 | public?abstract?class?Builder { //設置產品的不同部分,以獲得不同的產品 public?abstract?void?setPart(); //建造產品 public?abstract?Product buildProduct(); } |
????? 其中,setPart方法是零件的配置,什么是零件?其他的對象,獲得一個不同零件,或者不同的裝配順序就可能產生不同的產品。具體的建造者如代碼清單11-14所示。
代碼清單11-14 具體建造者
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public?class?ConcreteProduct extends Builder { private?Product product = new?Product(); //設置產品零件 public?void?setPart(){ /* * 產品類內的邏輯處理 */ } //組建一個產品 public?Product buildProduct() { return?product; } } |
????? 需要注意的是,如果有多個產品類就有幾個具體的建造者,而且這多個產品類具有相同接口或抽象類,參考我們上面的例子。
導演類如代碼清單11-15所示。
代碼清單11-15 導演類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public?class?Director { private?Builder builder = new?ConcreteProduct(); //構建不同的產品 public?Product getAProduct(){ builder.setPart(); /* * 設置不同的零件,產生不同的產品 */ return?builder.buildProduct(); } } |
????? 導演類就是起到封裝的作用,避免高層模塊深入到建造者內部的實現類。當然,在建造者模式比較龐大時,導演類可以有多個。
11.3 建造者模式的應用
????? 1. 建造者模式的優點
- 封裝性
????? 使用建造者模式可以使客戶端不必知道產品內部組成的細節,如例子中我們就不需要關心每一個具體的模型內部是如何實現的,產生的對象類型就是CarModel。
- 建造者獨立,容易擴展
????? BenzBuilder和BMWBuilder是相互獨立的,對系統的擴展非常有利。
- 便于控制細節風險
????? 由于具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響。
????? 2. 建造者模式的使用場景
- 相同的方法,不同的執行順序,產生不同的事件結果時,可以采用建造者模式。
- 多個部件或零件,都可以裝配到一個對象中,但是產生的運行結果又不相同時,則可以使用該模式。
- 產品類非常復雜,或者產品類中的調用順序不同產生了不同的效能,這個時候使用建造者模式是非常合適。
- 在對象創建過程中會使用到系統中的一些其它對象,這些對象在產品對象的創建過程中不易得到時,也可以采用建造者模式封裝該對象的創建過程。該種場景,只能是一個補償方法,因為一個對象不容易獲得,而在設計階段竟然沒有發覺,而要通過創建者模式柔化創建過程,本身已經違反設計最初目標。
????? 3. 建造者模式的注意事項
????? 建造者模式關注的是的零件類型和裝配工藝(順序),這是它與工廠方法模式最大不同的地方,雖然同為創建類模式,但是注重點不同。
11.4 建造者模式的擴展
????? 已經不用擴展了,因為我們在汽車模型制造的例子中已經對建造者模式進行了擴展,引入了模板方法模式,可能大家會比較疑惑,為什么在其他介紹設計模式的書籍上創建者模式并不是這樣說的,讀者請注意,建造者模式中還有一個角色沒有說明,就是零件,建造者怎么去建造一個對象?是零件的組裝,組裝順序不同對象效能也不同,這才是建造者模式要表達的核心意義,而怎么才能更好的達到這種效果呢?引入模板方法模式是一個非常簡單而有效的辦法。
????? 大家看到這里估計就開始犯嘀咕了,這個建造者模式和工廠模式非常相似呀,Yes,是的,是非常相似,但是記住一點你就可以游刃有余的使用了:建造者模式最主要功能是基本方法的調用順序安排,也就是這些基本方法已經實現了,通俗的說就是零件的裝配,順序不同產生的對象也不同;而工廠方法則重點是創建,創建零件時它的主要職責,你要什么對象我創造一個對象出來,組裝順序則不是他關心的。
11.5 最佳實踐
????? 再次說明,在使用建造者模式的時候考慮一下模板方法模式,別孤立的思考一個模式,僵化的套用一個模式會讓受害無窮!
如果你已經看懂本章節舉的例子,并認可這種建造者模式,那你就放心使用,比單獨使用某些書上的純建造者是高效、簡潔得多。
轉載于:https://www.cnblogs.com/jyx140521/archive/2012/12/18/2823264.html
總結
以上是生活随笔為你收集整理的设计模式-建造者模式(转自:http://www.cnblogs.com/cbf4life/archive/2010/01/14/1647710.html)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ios开发学习--列表(Table)效果
- 下一篇: 【转】如何在忘记CentOS的root密