<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之旅 廣告
                30.2 抽象工廠模式VS建造者模式 抽象工廠模式實現對產品家族的創建,一個產品家族是這樣的一系列產品:具有不同分類維度的產品組合,采用抽象工廠模式則是不需要關心構建過程,只關心什么產品由什么工廠生產即可。而建造者模式則是要求按照指定的藍圖建造產品,它的主要目的是通過組裝零配件而產生一個新產品,兩者的區別還是比較明顯的,但是還有讀者對這兩個模式產生混淆,我們通過一個例子說明兩者的差別。 現代化的汽車工廠能夠批量生產汽車(不考慮手工打造的豪華車)。不同的工廠生產不同的汽車,寶馬工廠生產寶馬牌子的車,奔馳工廠生產奔馳牌子的車。車不僅具有不同品牌,還有不同的用途分類,如商務車Van,運動型車SUV等,我們按照兩種設計模式分別實現車輛的生產過程。 30.2.1 按抽象工廠模式生產車輛 按照抽象工廠模式,首先需要定義一個抽象的產品接口即汽車接口,然后寶馬和奔馳分別實現該接口,由于它們只具有了一個品牌屬性,還沒有定義一個具體的型號,屬于對象的抽象層次,每個具體車型由其子類實現,如R系列的奔馳車是商務車,X系列的寶馬車屬于SUV,我們來看類圖,如圖30-3所示。 ![](https://box.kancloud.cn/2016-08-14_57b0036ceb742.jpg) 圖30-3 車輛生產的工廠類圖 在類圖中,產品類很簡單,我們從兩個維度看產品:品牌和車型,每個品牌下都有兩個車型,如寶馬SUV,寶馬商務車等,同時我們又建造了兩個工廠,一個專門生產寶馬車的寶馬工廠BMWFactory,一個是生產奔馳車的奔馳車生產工廠BenzFactory。當然,汽車工廠也有兩個不同的維度,可以建立這樣兩個工廠:一個專門生產SUV車輛的生產工廠,生產寶馬SUV和奔馳SUV,另外一個工廠專門生成商務車,分別是寶馬商務車和奔馳商務車,這樣設計在技術上是完全可行的,但是在業務上是不可行的,為什么?這是因為你看到過有一個工廠既能生產奔馳SUV也能生產寶馬SUV嗎?這是不可能的,因為業務受限,除非是國內的山寨工廠。我們先來看產品類,汽車接口如代碼清單30-12所示。 代碼清單30-12 汽車接口 public?interface?ICar?{ ?????//汽車的生產商,也就是牌子 ?????public?String?getBand(); ?????//汽車的型號 ?????public?String?getModel(); } 在產品接口中我們定義了車輛有兩個可以查詢的屬性:品牌和型號,奔馳車和寶馬車是兩個不同品牌的產品,但不夠具體,只是知道它們的品牌而已,還不能夠實例化,因此還是一個抽象類,如代碼清單30-13所示。 代碼清單30-13 抽象寶馬車 public?abstract?class?AbsBMW?implements?ICar?{ ?????private?final?static?String?BMW_BAND?=?"寶馬汽車"; ?????//寶馬車 ?????public?String?getBand()?{ ?????????????return?BMW_BAND; ?????} ?????//型號由具體的實現類實現 ?????public?abstract?String?getModel(); } 抽象產品類中實現了產品的類型定義,車輛的型號沒有實現,兩實現類分別實現商務車和運動型車,分別如代碼清單30-14、代碼清單30-15所示。 代碼清單30-14 寶馬商務車 public?class?BMWVan?extends?AbsBMW?{ ?????private?final?static?String?SEVENT_SEARIES?=?"7系列車型商務車"; ?????public?String?getModel()?{ ?????????????return?SEVENT_SEARIES; ?????} } 代碼清單30-15 寶馬SUV public?class?BMWSuv?extends?AbsBMW?{ ?????private?final?static?String?X_SEARIES?=?"X系列車型SUV"; ?????public?String?getModel()?{ ?????????????return?X_SEARIES; ?????} } 奔馳車與寶馬車類似,都已經有清晰品牌定義,但是型號還沒有確認,也是一個抽象的產品類,如代碼清單30-16所示。 代碼清單30-16 抽象奔馳車 public?abstract?class?AbsBenz?implements?ICar?{ ?????private?final?static?String?BENZ_BAND?=?"奔馳汽車"; ?????public?String?getBand()?{ ?????????????return?BENZ_BAND; ?????} ?????//具體型號由實現類完成 ?????public?abstract?String?getModel(); } 由于分類的標準是相同的,因此奔馳車也應該有商務車和運動車兩個類型,分別如代碼清單30-17和代碼清單30-18所示。 代碼清單30-17 奔馳商務車 public?class?BenzVan?extends?AbsBenz?{ ?????private?final?static?String?R_SERIES?=?"R系列商務車"; ?????public?String?getModel()?{ ?????????????return?R_SERIES; ?????} } 代碼清單30-18???奔馳SUV public?class?BenzSuv?extends?AbsBenz?{ ?????private?final?static?String?G_SERIES?=?"G系列SUV"; ?????public?String?getModel()?{ ?????????????return?G_SERIES; ?????} } 所有的產品類都已經實現了,剩下的工作就是要定義工廠類進行生產,由于產品類型多樣,也導致了必須有多個工廠類來生產不同產品,首先就需要定義一個抽象工廠,聲明每個工廠必須完成的職責,如代碼清單30-19所示。 代碼清單30-19 抽象工廠 public?interface?CarFactory?{ ?????//生產SUV ?????public?ICar?createSuv(); ?????//生產商務車 ?????public?ICar?createVan(); } 抽象工廠定義了每個工廠必須生產兩個類型車:SUV(運動車)和VAN(商務車),否則一個工廠就不能被實例化,我們來看寶馬車工廠,如代碼清單30-20所示。 代碼清單30-20 寶馬車工廠 public?class?BMWFactory?implements?CarFactory?{ ?????//生產SUV ?????public?ICar?createSuv()?{ ?????????????return?new?BMWSuv(); ?????} ?????//生產商務車 ?????public?ICar?createVan(){ ?????????????return?new?BMWVan(); ?????} } 很簡單,你要我生產寶馬商務車,沒問題,直接產生一個寶馬商務車對象,返回給調用者,這對調用者來說根本不需要關心到底是怎么生產的,它只要找到一個寶馬工廠,即可生產出自己需要的產品(汽車)。奔馳車工廠與此類似,如代碼清單30-21所示。 代碼清單30-21 奔馳車工廠 public?class?BenzFactory?implements?CarFactory?{ ?????//生產SUV ?????public?ICar?createSuv()?{ ?????????????return?new?BenzSuv(); ?????} ?????//生產商務車 ?????public?ICar?createVan(){ ?????????????return?new?BenzVan(); ?????} } 產品和工廠都具備了,剩下的工作就是建立一個場景類模擬調用者調用,如代碼清單30-22所示。 代碼清單30-22 場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????//要求生產一輛奔馳SUV ?????????????System.out.println("===要求生產一輛奔馳SUV==="); ?????????????//首先找到生產奔馳車的工廠 ?????????????System.out.println("A、找到奔馳車工廠"); ?????????????CarFactory?carFactory=?new?BenzFactory(); ?????????????//開始生產奔馳SUV ?????????????System.out.println("B、開始生產奔馳SUV"); ?????????????ICar?benzSuv?=?carFactory.createSuv(); ?????????????//生產完畢,展示一下車輛信息 ?????????????System.out.println("C、生產出的汽車如下:"); ?????????????System.out.println("汽車品牌:"+benzSuv.getBand()); ?????????????System.out.println("汽車型號:"?+?benzSuv.getModel()); ?????} } 運行結果如下所示: ===要求生產一輛奔馳SUV=== A、找到奔馳車工廠 B、開始生產奔馳SUV C、生產出的汽車如下: 汽車品牌:奔馳汽車 汽車型號:G系列SUV 對外界調用者來說,只要更換一個具備相同結構的對象,即可發生非常大的改變,如我們原本使用BenzFactory生產汽車,但是過了一段時間后,我們的系統需要生產寶馬汽車,這對系統來說不需要很大的改動,只要把工廠類使用BMWFactory代替即可,立刻可以生產出寶馬車,注意這里生產的是一輛完整的車,對于一個產品,只要給出產品代碼(車類型)即可生產,抽象工廠模式把一輛車認為是一個完整的、不可拆分的對象。它注重完整性,一個產品一旦找到一個工廠生產,那就是固定的型號,不會出現一個寶馬工廠生產奔馳車的情況。那現在的問題是我們就想要一輛混合的車型,如奔馳的引擎,寶馬的車輪,那該怎么處理呢?使用我們的建造者模式! 30.2.2 按建造者模式生產車輛 按照建造者模式設計一個生產車輛需要把車輛進行拆分,拆分成引擎和車輪兩部分,然后由建造者進行建造,想要什么車,你只要有設計圖紙就成,馬上可以制造一輛車出來。它注重的是對零件的裝配、組合、封裝,它從一個細微構件裝配角度看待一個對象。我們來看生產車輛的類圖,如圖30-4所示。 注意看我們類圖中的藍圖類Blueprint,它負責對產品建造過程定義。既然要生產產品,那必然要對產品進行一個描述,在類圖中我們定義了一個接口來描述汽車,如代碼清單30-23所示。 代碼清單30-23 車輛產品描述 public?interface?ICar?{ ?????//汽車車輪 ?????public?String?getWheel(); ?????//汽車引擎 ?????public?String?getEngine(); } ![](https://box.kancloud.cn/2016-08-14_57b0036d0f8a3.jpg) 圖30-4 建造者模式建造車輛 我們定義一輛車必須有車輪和引擎,具體的產品如代碼清單30-24所示。 代碼清單30-24 具體車輛 public?class?Car?implements?ICar?{ ?????//汽車引擎 ?????private?String?engine; ?????//汽車車輪 ?????private?String?wheel; ?????//一次性傳遞汽車需要的信息 ?????public?Car(String?_engine,String?_wheel){ ?????????????this.engine?=?_engine; ?????????????this.wheel?=?_wheel; ?????} ?????public?String?getEngine()?{ ?????????????return?engine; ?????} ?????public?String?getWheel()?{ ?????????????return?wheel; ?????} ?????public?String?toString(){ ?????????????return?"車的輪子是:"?+?wheel?+?"\n車的引擎是:"?+?engine; ?????} } 一個簡單的JavaBean定義產品的屬性,明確對產品的描述。我們繼續來思考,因為我們的產品是比較抽象的,它沒有指定引擎的型號,也沒有指定車輪的牌子,那么這樣的組合方式有很多,完全要靠建造者來建造,建造者說要生產一輛奔馳SUV那就得用奔馳的引擎和奔馳的車輪,該建造者對于一個具體的產品來說是絕對的權威,我們來描述一下建造者,如代碼清單30-25所示。 代碼清單30-25 抽象建造者 public?abstract?class?CarBuilder?{ ?????//待建造的汽車 ?????private?ICar?car; ?????//設計藍圖 ?????private?Blueprint?bp; ?????public?Car?buildCar(){ ?????????????//按照順序生產一輛車 ?????????????return?new?Car(buildEngine(),buildWheel()); ?????} ?????//接收一份設計藍圖 ?????public?void?receiveBlueprint(Blueprint?_bp){ ?????????????this.bp?=?_bp; ?????} ?????//查看藍圖,只有真正的建造者才可以查看藍圖 ?????protected?Blueprint?getBlueprint(){ ?????????????return?bp; ?????} ?????//建造車輪 ?????protected?abstract?String?buildWheel(); ?????//建造引擎 ?????protected?abstract?String?buildEngine(); } 看到Blueprint類了,它中文的意思是“藍圖”,你要建造一輛車必須有一個設計樣稿或者藍圖吧,否則怎么生產?怎么裝配?該類就是一個可參考的生產樣本,如代碼清單30-26所示。 代碼清單30-26 生產藍圖 public?class?Blueprint?{ ?????//車輪的要求 ?????private?String?wheel; ?????//引擎的要求 ?????private?String?engine; ?????public?String?getWheel()?{ ?????????????return?wheel; ?????} ?????public?void?setWheel(String?wheel)?{ ?????????????this.wheel?=?wheel; ?????} ?????public?String?getEngine()?{ ?????????????return?engine; ?????} ?????public?void?setEngine(String?engine)?{ ?????????????this.engine?=?engine; ?????}????? } 這和一個具體的產品Car類是一樣的?錯,不一樣!它是一個藍圖,是一個可以參考的模板,有一個藍圖可以設計出非常多的產品,如有一個R系統的奔馳商務車設計藍圖,我們就可以生產出一系列的奔馳車。它指導我們的產品生產,而不是一個具體的產品。我們來看寶馬車建造車間,如代碼清單30-27所示。 代碼清單30-27 寶馬車建造車間 public?class?BMWBuilder?extends?CarBuilder?{ ?????public?String?buildEngine()?{ ?????????????return?super.getBlueprint().getEngine(); ?????} ?????public?String?buildWheel()?{ ?????????????return?super.getBlueprint().getWheel(); ?????} } 這是非常簡單的類。只要獲得一個藍圖,然后按照藍圖制造引擎和車輪即可,剩下的事情就交給抽象的建造者進行裝配。奔馳車間與此類似,如代碼清單30-28所示。 代碼清單30-28 奔馳車建造車間 public?class?BenzBuilder?extends?CarBuilder?{ ?????public?String?buildEngine()?{ ?????????????return?super.getBlueprint().getEngine(); ?????} ?????public?String?buildWheel()?{ ?????????????return?super.getBlueprint().getWheel(); ?????} } 兩個建造車間都已經完成,那現在的問題就變成了怎么讓車間運作,誰來編寫藍圖?誰來協調生產車間?誰來對外提供最終產品?于是導演類出場了,它不僅僅有每個車間需要的設計藍圖,還具有指導不同車間裝配順序的職責,如代碼清單30-29所示。 代碼清單30-29 導演類 public?class?Director?{ ?????//聲明對建造者的引用 ?????private?CarBuilder?benzBuilder?=?new?BenzBuilder(); ?????private?CarBuilder?bmwBuilder?=?new?BMWBuilder(); ?????//生產奔馳SUV ?????public?ICar?createBenzSuv(){ ?????????????//制造出汽車 ?????????????return?createCar(benzBuilder,?"benz的引擎",?"benz的輪胎"); ?????} ?????//生產出一輛寶馬商務車 ?????public?ICar?createBMWVan(){ ?????????????return?createCar(benzBuilder,?"BMW的引擎",?"BMW的輪胎"); ?????} ?????//生產出一個混合車型 ?????public?ICar?createComplexCar(){?????????? ?????????????return?createCar(bmwBuilder,?"BMW的引擎",?"benz的輪胎"); ?????} ?????//生產車輛 ?????private?ICar?createCar(CarBuilder?_carBuilder,String?engine,String?wheel){ ?????????????//導演懷揣藍圖 ?????????????Blueprint?bp?=?new?Blueprint(); ?????????????bp.setEngine(engine); ?????????????bp.setWheel(wheel); ?????????????System.out.println("獲得生產藍圖"); ?????????????_carBuilder.receiveBlueprint(bp); ?????????????return?_carBuilder.buildCar(); ?????} } 這里有一個私有方法createCar,其作用是減少導演類中的方法對藍圖的依賴,全部由該方法來完成。我們編寫一個場景類,如代碼清單30-30所示。 代碼清單30-30 場景類 public?class?Client?{ ?????public?static?void?main(String[]?args)?{ ?????????????//定義出導演類 ?????????????Director?director?=new?Director(); ?????????????//給我一輛奔馳車SUV ?????????????System.out.println("===制造一輛奔馳SUV==="); ?????????????ICar?benzSuv?=?director.createBenzSuv(); ?????????????System.out.println(benzSuv); ?????????????//給我一輛寶馬商務車 ?????????????System.out.println("\n===制造一輛寶馬商務車==="); ?????????????ICar?bmwVan?=?director.createBMWVan(); ?????????????System.out.println(bmwVan); ?????????????//給我一輛混合車型 ?????????????System.out.println("\n===制造一輛混合車==="); ?????????????ICar?complexCar?=?director.createComplexCar(); ?????????????System.out.println(complexCar); ?????} } 場景類只要找到導演類(也就是車間主任了)說給我制造一輛這樣的寶馬車,車間主任馬上通曉你的意圖,設計了一個藍圖,然后命令建造車間拼命加班加點建造,最終返回給你一件最新出品的產品,運行結果如下所示: ===制造一輛奔馳SUV=== 獲得生產藍圖 車的輪子是:benz的輪胎 車的引擎是:benz的引擎 ===制造一輛寶馬商務車=== 獲得生產藍圖 車的輪子是:BMW的輪胎 車的引擎是:BMW的引擎 ===制造一輛混合車=== 獲得生產藍圖 車的輪子是:benz的輪胎 車的引擎是:BMW的引擎 注意最后一個運行結果片段,我們可以立刻生產出一輛混合車型,只要有設計藍圖,這非常容易實現。反觀我們的抽象工廠模式,它是不可能實現該功能的,因為它更關注的是整體,而不關注到底用的是奔馳引擎還是寶馬引擎,而我們的建造者模式卻可以很容易地實現該設計,市場信息變更了,我們就可以立刻跟進,生產出客戶需要的產品。 30.2.3 最佳實踐 注意看上面的描述,我們在抽象工廠模式中使用“工廠”來描述構建者,而在建造者模式中使用“車間”來描述構建者,其實我們已經在說它們兩者的區別了,抽象工廠模式就好比是一個一個的工廠,寶馬車工廠生產寶馬SUV和寶馬VAN,奔馳車工廠生產奔馳車SUV和奔馳VAN,它是從一個更高層次去看對象的構建,具體到工廠內部還有很多的車間,如制造引擎的車間、裝配引擎的車間等,但這些都是隱藏在工廠內部的細節,對外不公布。也就是對領導者來說,他只要關心一個工廠到底是生產什么產品的,不用關心具體怎么生產。而建造者模式就不同了,它是由車間組成,不同的車間完成不同的創建和裝配任務,一個完整的汽車生產過程需要引擎制造車間、引擎裝配車間的配合才能完成,它們配合的基礎就是設計藍圖,而這個藍圖是掌握在車間主任(導演類)手中,它給建造車間什么藍圖就能生產什么產品,建造者模式更關心建造過程。雖然從外界看來一個車間還是生產車輛,但是這個車間的轉型是非常快的,只要重新設計一個藍圖,即可產生不同的產品,這有賴于建造者模式的功勞。 相對來說,抽象工廠模式比建造者模式的尺度要大,它關注產品整體,而建造者模式關注構建過程,因此建造者模式可以很容易地構建出一個嶄新的產品,只要導演類能夠提供具體的工藝流程。也正因為如此,兩者的應用場景截然不同,如果希望屏蔽對象的創建過程,只提供一個封裝良好的對象,則可以選擇抽象工廠方法模式。而建造者模式可以用在構件的裝配方面,如通過裝配不同的組件或者相同組件的不同順序,可以產生出一個新的對象,它可以產生一個非常靈活的架構,方便地擴展和維護系統。
                  <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>

                              哎呀哎呀视频在线观看