<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                第11章 建造者模式 11.1 變化是永恒的 又是一個周三,快要下班了,老大突然拉住我,喜滋滋地告訴我:“××公司很滿意我們做的模型,又簽訂了一個合同,把奔馳、寶馬的車輛模型都交給我們公司制作了,不過這次又額外增加了一個新需求:汽車的啟動、停止、喇叭聲音、引擎聲音都由客戶自己控制,他想什么順序就什么順序,這個沒問題吧?” 那任務又是一個時間緊、工程量大的項目,為什么是“又”呢?因為基本上每個項目都是如此,我該怎么來完成這個任務呢? 首先,我們分析一下需求,奔馳、寶馬都是一個產品,它們有共有的屬性,××公司關心的是單個模型的運行過程:奔馳模型A是先有引擎聲音,然后再響喇叭;奔馳模型B是先啟動起來,然后再有引擎聲音,這才是××公司要關心的。那到我們老大這邊呢,就是滿足人家的要求,要什么順序就立馬能產生什么順序的模型出來。我就負責把老大的要求實現出來,而且還要是批量的,也就是說××公司下單訂購寶馬A車模,我們老大馬上就找我“生產一個這樣的車模,啟動完畢后,喇叭響一下”,然后我們就準備開始批量生產這些模型。由我生產出N多個奔馳和寶馬車輛模型,這些車輛模型都有run()方法,但是具體到每一個模型的run()方法中間的執行任務的順序是不同的,老大說要啥順序,我就給啥順序,最終客戶買走后只能是既定的模型。好,需求還是比較復雜,我們先一個一個地解決,先從找一個最簡單的切入點——產品類,每個車都是一個產品,如圖11-1所示。 ![](https://box.kancloud.cn/2016-08-14_57b00361b1bc1.jpg) 圖11-1 汽車模型類圖 類圖比較簡單,在CarModel中我們定義了一個setSequence方法,車輛模型的這幾個動作要如何排布,是在這個ArrayList中定義的。然后run()方法根據sequence定義的順序完成指定的順序動作,與第10章介紹的模板方法模式是不是非常類似?好,我們先看CarModel源代碼,如代碼清單11-1所示。 代碼清單11-1 車輛模型的抽象類 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?sequence){ ?????????????this.sequence?=?sequence; ?????} } CarModel的設計原理是這樣的,setSequence方法是允許客戶自己設置一個順序,是要先啟動響一下喇叭再跑起來,還是要先響一下喇叭再啟動。對于一個具體的模型永遠都固定的,但是對N多個模型就是動態的了。在子類中實現父類的基本方法,run()方法讀取sequence,然后遍歷sequence中的字符串,哪個字符串在先,就先執行哪個方法。 兩個實現類分別實現父類的基本方法,奔馳模型如代碼清單11-2所示。 代碼清單11-2 奔馳模型代碼 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 寶馬模型代碼 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("寶馬車應該這樣停車..."); ?????} } 兩個產品的實現類都完成,我們來模擬一下××公司的要求:生產一個奔馳模型,要求跑的時候,先發動引擎,然后再掛擋啟動,然后停下來,不需要喇叭。這個需求很容易滿足,我們增加一個場景類實現該需求,如代碼清單11-4所示。 代碼清單11-4 奔馳模型代碼 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????/* ??????????????*?客戶告訴XX公司,我要這樣一個模型,然后XX公司就告訴我老大 ??????????????*?說要這樣一個模型,這樣一個順序,然后我就來制造 ??????????????*/ ?????????????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();???????????????? ?????} } 運行結果如下所示: 奔馳車的引擎是這個聲音的... 奔馳車跑起來是這個樣子的... 奔馳車應該這樣停車... 看,我們組裝了這樣的一輛汽車,滿足了××公司的需求。但是想想我們的需求,汽車的動作執行順序是要能夠隨意調整的。我們只滿足了一個需求,還有下一個需求呀,然后是第二個寶馬模型,只要啟動、停止,其他的什么都不要;第三個模型,先喇叭,然后啟動,然后停止;第四個……直到把你逼瘋為止,那怎么辦?我們就一個一個地來寫場景類滿足嗎?不可能了,那我們要想辦法來解決這個問題,有了!我們為每種模型產品模型定義一個建造者,你要啥順序直接告訴建造者,由建造者來建造,于是乎我們就有了如圖11-2所示的類圖。 ![](https://box.kancloud.cn/2016-08-14_57b00361cbcd0.jpg) 圖11-2 增加了建造者的汽車模型類圖 增加了一個CarBuilder抽象類,由它來組裝各個車模,要什么類型什么順序的車輛模型,都由相關的子類完成。首先編寫CarBuilder代碼,如代碼清單11-5所示。 代碼清單11-5 抽象汽車組裝者 public?abstract?class?CarBuilder?{ ?????//建造一個模型,你要給我一個順序要求,就是組裝順序 ?????public?abstract?void?setSequence(ArrayList<String>?sequence); ?????//設置完畢順序后,就可以直接拿到這個車輛模型 ?????public?abstract?CarModel?getCarModel(); } 很簡單,每個車輛模型都要有確定的運行順序,然后才能返回一個車輛模型。奔馳車的組裝者如代碼清單11-6所示。 代碼清單11-6 奔馳車組裝者 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 寶馬車組裝者 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 修改后的場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????/* ??????????????*?客戶告訴XX公司,我要這樣一個模型,然后XX公司就告訴我老大 ??????????????*?說要這樣一個模型,這樣一個順序,然后我就來制造 ??????????????*/ ?????????????//存放run的順序 ?????????????ArrayList<String>?sequence?=?new?ArrayList<String>(); ?????????????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 相同順序的寶馬車的場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????//存放run的順序 ?????????????ArrayList<String>?sequence?=?new?ArrayList<String>(); ?????????????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)簡單了很多。我們在做項目時,經常會有一個共識:需求是無底洞,是無理性的,不可能你告訴它不增加需求就不增加,這4個過程(start、stop、alarm、engine boom)按照排列組合有很多種,××公司可以隨意組合,它要什么順序的車模我就必須生成什么順序的車模,客戶可是上帝!那我們不可能預知他們要什么順序的模型呀,怎么辦?封裝一下,找一個導演,指揮各個事件的先后順序,然后為每種順序指定一個代碼,你說一種我們立刻就給你生產處理,好方法,厲害!我們先修改一下類圖,如圖11-3所示。 ![](https://box.kancloud.cn/2016-08-14_57b00361e3f50.jpg) 圖11-3 完整汽車模型類圖 類圖看著復雜了,但還是比較簡單,我們增加了一個Director類,負責按照指定的順序生產模型,其中方法說明如下: ● getABenzModel方法 組建出A型號的奔馳車輛模型,其過程為只有啟動(start)、停止(stop)方法,其他的引擎聲音、喇叭都沒有。 ● getBBenzModel方法 組建出B型號的奔馳車,其過程為先發動引擎(engine boom),然后啟動,再然后停車,沒有喇叭。 ● getCBMWModel方法 組建出C型號的寶馬車,其過程為先喇叭叫一下(alarm),然后啟動,再然后是停車,引擎不轟鳴。 ● getDBMWModel方法 組建出D型號的寶馬車,其過程就一個啟動,然后一路跑到黑,永動機,沒有停止方法,沒有喇叭,沒有引擎轟鳴。 其他的E型號、F型號……可以有很多,啟動、停止、喇叭、引擎轟鳴這4個方法在這個類中可以隨意地自由組合。Director類如代碼清單11-10所示。 代碼清單11-10 導演類 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類型的奔馳車1萬輛,B類型的奔馳車100萬輛,C類型的寶馬車1000萬輛,D類型的不需要,非常容易處理,如代碼清單11-11所示。 代碼清單11-11 導演類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????Director?director?=?new?Director();???????????????? ?????????????//1萬輛A類型的奔馳車 ?????????????for(int?i=0;i<10000;i++){ ?????????????????????director.getABenzModel().run(); ?????????????}?????????? ?????????????//100萬輛B類型的奔馳車 ?????????????for(int?i=0;i<1000000;i++){ ?????????????????????director.getBBenzModel().run(); ?????????????}?????????? ?????????????//1000萬輛C類型的寶馬車 ?????????????for(int?i=0;i<10000000;i++){ ?????????????????????director.getCBMWModel().run(); ?????????????} ?????} } 清晰、簡單吧,我們寫程序重構的最終目的就是:簡單、清晰。代碼是讓人看的,不是寫完就完事了,我一直在教育我帶的團隊成員,Java程序不是像我們前輩寫二進制代碼、匯編一樣,寫完基本上就自己能看懂,別人看就跟看天書一樣,現在的高級語言,要像寫中文漢字一樣,你寫的,別人能看懂。這就是建造者模式。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看