30.1 工廠方法模式VS建造者模式
工廠方法模式注重的是整體對象的創建方法,而建造者模式注重的是部件構建的過程,旨在通過一步一步地精確構造創建出一個復雜的對象。我們舉個簡單例子來說明兩者的差異,如要制造一個超人,如果使用工廠方法模式,直接產生出來的就是一個力大無窮、能夠飛翔、內褲外穿的超人;而如果使用建造者模式,則需要組裝手、頭、腳、軀干等部分,然后再把內褲外穿,于是一個超人就誕生了。純粹使用文字來描述比較枯燥,我們還是通過程序來更加清晰地認識兩者的差別。
30.1.1 按工廠方法建造超人
首先,按照工廠方法模式創建出一個超人,類圖如圖30-1所示。

圖30-1 按工廠方法建造超人
類圖中我們按照年齡段把超人分為兩種類型:成年超人(如克拉克、超能先生)和未成年超人(如Dash、Jack)。這是一個非常正宗的工廠方法模式,定義一個產品的接口,然后再定義兩個實現,通過超人制造工廠制造超人。想想看我們對超人最大印象是什么?當然是他的超能力,我們以specialTalent(特殊天賦)方法來代表,先看抽象產品類,如代碼清單30-1所示。
代碼清單30-1 超人接口
public?interface?ISuperMan?{
?????//每個超人都有特殊技能
?????public?void?specialTalent();
}
產品的接口定義好了,我們再來看具體的產品。先看成年超人,很簡單,如代碼清單30-2所示。
代碼清單30-2 成年超人
public?class?AdultSuperMan?implements?ISuperMan?{
?????//超能先生
?????public?void?specialTalent()?{
?????????????System.out.println("超人力大無窮");
?????}
}
未成年超人的代碼如代碼清單30-3所示。
代碼清單30-3 未成年超人
public?class?ChildSuperMan?implements?ISuperMan?{
?????//超能先生的三個孩子
?????public?void?specialTalent()?{
?????????????System.out.println("小超人的能力是刀槍不入、快速運動");
?????}
}
產品都具備,那我們編寫一個工廠類,其意圖就是生產超人,具體是成年超人還是未成年超人,則由客戶端決定,如代碼清單30-4所示。
代碼清單30-4 超人制造工廠
public?class?SuperManFactory?{
?????//定義一個生產超人的工廠
?????public?static?ISuperMan?createSuperMan(String?type){
?????????????//根據輸入參數產生不同的超人
?????????????if(type.equalsIgnoreCase("adult")){
?????????????????????//生產成人超人
?????????????????????return?new?AdultSuperMan();
?????????????}else?if(type.equalsIgnoreCase("child")){
?????????????????????//生產未成年超人
?????????????????????return?new?ChildSuperMan();
?????????????}else{
?????????????????????return?null;
?????????????}
?????}
}
產品有了,工廠類也有了,剩下的工作就是開始生產超人。這也非常簡單,如代碼清單30-5所示。
代碼清單30-5 場景類
public?class?Client?{
?????//模擬生產超人
?????public?static?void?main(String[]?args)?{
?????????????//生產一個成年超人
?????????????ISuperMan?adultSuperMan?=?SuperManFactory.createSuperMan("adult");
?????????????//展示一下超人的技能
?????????????adultSuperMan.specialTalent();
?????}
}
建立了一個超人生產工廠,年復一年地生產超人,對于具體生產出的產品,不管是成年超人還是未成年超人,都是一個模樣:深藍色緊身衣、胸前S標記、內褲外穿,沒有特殊的地方。但是我們的目的達到了——生產出超人,拯救全人類,這就是我們的意圖。具體怎么生產、怎么組裝,這不是工廠方法模式要考慮的,也就是說,工廠模式關注的是一個產品整體,生產出的產品應該具有相似的功能和架構。
注意 通過工廠方法模式生產出對象,然后由客戶端進行對象的其他操作,但是并不代表所有生產出的對象都必須具有相同的狀態和行為,它是由產品所決定。
30.1.2 按建造者模式建造超人
我們再來看看建造者模式是如何生產超人的,如圖30-2所示。

圖30-2 按建造者模式生產超人
又是一個典型的建造者模式!哎,不對呀!通用模式上抽象建造者與產品類沒有關系呀!是的,我們當然可以加強了,我們在抽象建造者上使用了模板方法模式,每一個建造者都必須返回一個產品,但是產品是如何制造的,則由各個建造者自己負責。我們來看看程序,先看產品類,如代碼清單30-6所示。
代碼清單30-6 超人產品
public?class?SuperMan?{
?????//超人的軀體
?????private?String?body;
?????//超人的特殊技能
?????private?String?specialTalent;
?????//超人的標志
?????private?String?specialSymbol;
?????public?String?getBody()?{
?????????????return?body;
?????}
?????public?void?setBody(String?body)?{
?????????????this.body?=?body;
?????}
?????public?String?getSpecialTalent()?{
?????????????return?specialTalent;
?????}
?????public?void?setSpecialTalent(String?specialTalent)?{
?????????????this.specialTalent?=?specialTalent;
?????}
?????public?String?getSpecialSymbol()?{
?????????????return?specialSymbol;
?????}
?????public?void?setSpecialSymbol(String?specialSymbol)?{
?????????????this.specialSymbol?=?specialSymbol;
?????}
}
超人這個產品是由三部分組成:軀體、特殊技能、身份標記,這就類似于電子產品,首先生產出一個固件,然后再安裝一個靈魂(軟件驅動),最后再打上產品標簽。完事了!一個嶄新的產品就誕生了!我們的超人也是這樣生產的,先生產一個普通的軀體,然后注入特殊技能,最后打上S標簽,一個超人生產完畢。我們再來看一下建造者的抽象定義,如代碼清單30-7所示。
代碼清單30-7 抽象建造者
public?abstract?class?Builder?{
?????//定義一個超人的應用
?????protected?final?SuperMan?superMan?=?new?SuperMan();
?????//構建出超人的軀體
?????public?void?setBody(String?body){
?????????????this.superMan.setBody(body);
?????}
?????//構建出超人的特殊技能
?????public?void?setSpecialTalent(String?st){
?????????????this.superMan.setSpecialTalent(st);
?????}
?????//構建出超人的特殊標記
?????public?void?setSpecialSymbol(String?ss){
?????????????this.superMan.setSpecialSymbol(ss);
?????}
?????//構建出一個完整的超人
?????public?abstract?SuperMan?getSuperMan();
}
一個典型的模板方法模式,超人的各個部件(軀體、靈魂、標志)都準備好了,具體怎么組裝則是由實現類來決定。我們先來看成年超人,如代碼清單30-8所示。
代碼清單30-8 成年超人建造者
public?class?AdultSuperManBuilder?extends?Builder?{
?????@Override
?????public?SuperMan?getSuperMan()?{
?????????????super.setBody("強壯的軀體");
?????????????super.setSpecialTalent("會飛行");
?????????????super.setSpecialSymbol("胸前帶S標記");
?????????????return?super.superMan;
?????}
}
怎么回事?在第11章中講解建造者模式的時候在產品中使用了模板方法模式,在這里怎么把模板方法模式遷移到建造者了?怎么會這樣?你是不是在發出這樣的疑問?別疑問了!設計模式只是提供了一個解決問題的意圖:復雜對象的構建與它的表示分離,而沒有具體定出一個設計模式必須是這樣的實現,必須是這樣的代碼,靈活運用模式才是其根本,別學死板了。
我們繼續看未成年超人的建造者,如代碼清單30-9所示。
代碼清單30-9 未成年超人建造者
public?class?ChildSuperManBuilder?extends?Builder?{
?????@Override
?????public?SuperMan?getSuperMan()?{
?????????????super.setBody("強壯的軀體");
?????????????super.setSpecialTalent("刀槍不入");
?????????????super.setSpecialSymbol("胸前帶小S標記");
?????????????return?super.superMan;
?????}
}
大家注意看我們這兩個具體的建造者,它們都關注了產品的各個部分,在某些應用場景下甚至會關心產品的構建順序,即使是相同的部件,裝配順序不同,產生的結果也不同,這也正是建造者模式的意圖:通過不同的部件、不同裝配產生不同的復雜對象。我們再來看導演類,如代碼清單30-10所示。
代碼清單30-10 導演類
public?class?Director?{
?????//兩個建造者的應用
?????private?static?Builder??adultBuilder?=?new?AdultSuperManBuilder();
?????//未成年超人的建造者
?????private?static?Builder?childBuilder?=?new?ChildSuperManBuilder();
?????//建造一個成年、會飛行的超人
?????public?static?SuperMan?getAdultSuperMan(){
?????????????return?adultBuilder.getSuperMan();
?????}
?????//建造一個未成年、刀槍不入的超人
?????public?static?SuperMan?getChildSuperMan(){
?????????????return?childBuilder.getSuperMan();
?????}
}
這很簡單,不多說了!看看場景類是如何調用的,如代碼清單30-11所示。
代碼清單30-11 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????//建造一個成年超人
?????????????SuperMan?adultSuperMan?=?Director.getAdultSuperMan();
?????????????//展示一下超人的信息
?????????????adultSuperMan.getSpecialTalent();
?????}
}
這個場景類的寫法與工廠方法模式是相同的,但是你可以看到,在建立超人的過程中,建造者必須關注超人的各個部件,而工廠方法模式則只關注超人的整體,這就是兩者的區別。
30.1.3 最佳實踐
工廠方法模式和建造者模式都屬于對象創建類模式,都用來創建類的對象。但它們之間的區別還是比較明顯的。
● 意圖不同
在工廠方法模式里,我們關注的是一個產品整體,如超人整體,無須關心產品的各部分是如何創建出來的;但在建造者模式中,一個具體產品的產生是依賴各個部件的產生以及裝配順序,它關注的是“由零件一步一步地組裝出產品對象”。簡單地說,工廠模式是一個對象創建的粗線條應用,建造者模式則是通過細線條勾勒出一個復雜對象,關注的是產品組成部分的創建過程。
● 產品的復雜度不同
工廠方法模式創建的產品一般都是單一性質產品,如成年超人,都是一個模樣,而建造者模式創建的則是一個復合產品,它由各個部件復合而成,部件不同產品對象當然不同。這不是說工廠方法模式創建的對象簡單,而是指它們的粒度大小不同。一般來說,工廠方法模式的對象粒度比較粗,建造者模式的產品對象粒度比較細。
兩者的區別有了,那在具體的應用中,我們該如何選擇呢?是用工廠方法模式來創建對象,還是用建造者模式來創建對象,這完全取決于我們在做系統設計時的意圖,如果需要詳細關注一個產品部件的生產、安裝步驟,則選擇建造者,否則選擇工廠方法模式。
- 前言
- 第一部分 大旗不揮,誰敢沖鋒——6大設計原則全新解讀
- 第1章 單一職責原則
- 1.2 絕殺技,打破你的傳統思維
- 1.3 我單純,所以我快樂
- 1.4 最佳實踐
- 第2章 里氏替換原則
- 2.2 糾紛不斷,規則壓制
- 2.3 最佳實踐
- 第3章 依賴倒置原則
- 3.2 言而無信,你太需要契約
- 3.3 依賴的三種寫法
- 3.4 最佳實踐
- 第4章 接口隔離原則
- 4.2 美女何其多,觀點各不同
- 4.3 保證接口的純潔性
- 4.4 最佳實踐
- 第5章 迪米特法則
- 5.2 我的知識你知道得越少越好
- 5.3 最佳實踐
- 第6章 開閉原則
- 6.2 開閉原則的廬山真面目
- 6.3 為什么要采用開閉原則
- 6.4 如何使用開閉原則
- 6.5 最佳實踐
- 第二部分 真刀實槍 ——23種設計模式完美演繹
- 第7章 單例模式
- 7.2 單例模式的定義
- 7.3 單例模式的應用
- 7.4 單例模式的擴展
- 7.5 最佳實踐
- 第8章 工廠方法模式
- 8.2 工廠方法模式的定義
- 8.3 工廠方法模式的應用
- 8.4 工廠方法模式的擴展
- 8.5 最佳實踐
- 第9章 抽象工廠模式
- 9.2 抽象工廠模式的定義
- 9.3 抽象工廠模式的應用
- 9.4 最佳實踐
- 第10章 模板方法模式
- 10.2 模板方法模式的定義
- 10.3 模板方法模式的應用
- 10.4 模板方法模式的擴展
- 10.5 最佳實踐
- 第11章 建造者模式
- 11.2 建造者模式的定義
- 11.3 建造者模式的應用
- 11.4 建造者模式的擴展
- 11.5 最佳實踐
- 第12章 代理模式
- 12.2 代理模式的定義
- 12.3 代理模式的應用
- 12.4 代理模式的擴展
- 12.5 最佳實踐
- 第13章 原型模式
- 13.2 原型模式的定義
- 13.3 原型模式的應用
- 13.4 原型模式的注意事項
- 13.5 最佳實踐
- 第14章 中介者模式
- 14.2 中介者模式的定義
- 14.3 中介者模式的應用
- 14.4 中介者模式的實際應用
- 14.5 最佳實踐
- 第15章 命令模式
- 15.2 命令模式的定義
- 15.3 命令模式的應用
- 15.4 命令模式的擴展
- 15.5 最佳實踐
- 第16章 責任鏈模式
- 16.2 責任鏈模式的定義
- 16.3 責任鏈模式的應用
- 16.4 最佳實踐
- 第17章 裝飾模式
- 17.2 裝飾模式的定義
- 17.3 裝飾模式應用
- 17.4 最佳實踐
- 第18章 策略模式
- 18.2 策略模式的定義
- 18.3 策略模式的應用
- 18.4 策略模式的擴展
- 18.5 最佳實踐
- 第19章 適配器模式
- 19.2 適配器模式的定義
- 19.3 適配器模式的應用
- 19.4 適配器模式的擴展
- 19.5 最佳實踐
- 第20章 迭代器模式
- 20.2 迭代器模式的定義
- 20.3 迭代器模式的應用
- 20.4 最佳實踐
- 第21章 組合模式
- 21.2 組合模式的定義
- 21.3 組合模式的應用
- 21.4 組合模式的擴展
- 21.5 最佳實踐
- 第22章 觀察者模式
- 22.2 觀察者模式的定義
- 22.3 觀察者模式的應用
- 22.4 觀察者模式的擴展
- 22.5 最佳實踐
- 第23章 門面模式
- 23.2 門面模式的定義
- 23.3 門面模式的應用
- 23.4 門面模式的注意事項
- 23.5 最佳實踐
- 第24章 備忘錄模式
- 24.2 備忘錄模式的定義
- 24.3 備忘錄模式的應用
- 24.4 備忘錄模式的擴展
- 24.5 最佳實踐
- 第25章 訪問者模式
- 25.2 訪問者模式的定義
- 25.3 訪問者模式的應用
- 25.4 訪問者模式的擴展
- 25.5 最佳實踐
- 第26章 狀態模式
- 26.2 狀態模式的定義
- 26.3 狀態模式的應用
- 第27章 解釋器模式
- 27.2 解釋器模式的定義
- 27.3 解釋器模式的應用
- 27.4 最佳實踐
- 第28章 享元模式
- 28.2 享元模式的定義
- 28.3 享元模式的應用
- 28.4 享元模式的擴展
- 28.5 最佳實踐
- 第29章 橋梁模式
- 29.2 橋梁模式的定義
- 29.3 橋梁模式的應用
- 29.4 最佳實踐
- 第三部分 誰的地盤誰做主 ——設計模式PK
- 第30章 創建類模式大PK
- 30.1 工廠方法模式VS建造者模式
- 30.2 抽象工廠模式VS建造者模式
- 第31章 結構類模式大PK
- 31.1 代理模式VS裝飾模式
- 31.2 裝飾模式VS適配器模式
- 第32章 行為類模式大PK
- 32.1 命令模式VS策略模式
- 32.2 策略模式VS狀態模式
- 32.3 觀察者模式VS責任鏈模式
- 第33章 跨戰區PK
- 33.1 策略模式VS橋梁模式
- 33.2 門面模式VS中介者模式
- 33.3 包裝模式群PK
- 第四部分 完美世界 ——設計模式混編
- 第34章 命令模式+責任鏈模式
- 34.2 混編小結
- 第35章 工廠方法模式+策略模式
- 35.2 混編小結
- 第36章 觀察者模式+中介者模式
- 36.2 混編小結
- 第五部分 擴展篇
- 第37章 MVC框架
- 37.2 最佳實踐
- 第38章 新模式
- 38.1 規格模式
- 38.2 對象池模式
- 38.3 雇工模式
- 38.4 黑板模式
- 38.5 空對象模式
- 附錄 23種設計模式彩圖