Java設計模式之簡單工廠、工廠方法和抽象工廠
本文由碼農網 – 魯阿皓原創,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃!
在前面的學習中(參見前面的部落格),我們學到了很多OO原則:
- 封裝變化
- 多用組合,少用繼承
- 針對介面/超類程式設計,不針對實現程式設計
- 鬆耦合
- 開閉原則
讓我們從一個簡單的類開始,看看如何將之改造成符合OO原則的類以及工廠模式在解耦中的威力。
class FoodStore { public Food orderFood() //通過此方法顧客從食物商店中得到食物 { Food food=new Food(); food.prepare(); // 準備食物 food.cut(); // 將食物切好 food.box(); // 包裝好 return food; } }
這樣寫還不夠,食物店裡又不是隻有一種food,我們要讓食物店提供更多!
class FoodStore { public Food orderFood(String type) { Food food = null; if (type.equals("bread")) { food = new bread(); } else if(type.endsWith("chicken")) { food=new chicken(); } food.prepare(); food.cut(); food.box(); return food; } }
這樣我們讓食物店提供了麵包和雞肉,他們分別是Food的子類,那我們要在新增一種食物(pizza)呢?這就又需要修改FoodStore的程式碼!這可不符合開閉原則!但是,從上面兩個不同版本的類來看,可以分析出類中變化的部分:食物型別!
既然我們已經找到了變化的部分,根據封裝變化的原則,就把這部分(物件的建立)獨立開來。
class SimpleFactory { public Food creatFood(String type) { Food food = null; if (type.equals("bread")) { food = new bread(); } else if(type.endsWith("chicken")) { food=new chicken(); } return food; } }
這樣,我們就完成了今天第一個“模式”——簡單工廠,在這個過程中,其實我們只做了一件事:將foodstore中建立物件的部分與其隔離開(其實工廠模式的目的就是封裝物件的建立),即:封裝變化
下面是封裝之後的FoodStore:
class FoodStore { SimpleFactory factory; public FoodStore(SimpleFactory factory) { this.factory=factory; } public Food orderFood(String type) { Food food = factory.creatFood(type); food.prepare(); food.cut(); food.box(); return food; } }
由於建立物件的過程交給了工廠,所以如果再新增食物類別,只需要修改SimpleFactory類,這樣FoodStore就符合了對修改關閉原則!
簡單工廠已經很厲害了!但是還不足以應付所有的情況,讓我們看看工廠方法和抽象工廠的表現。
問題1:假如有很多商店都向簡單工廠去取物件,那麼所有商店取得的麵包物件和雞肉物件都是一樣的!我們想讓不同商店裡取得不同口味的食物!
問題2:假如一個商店想要出售兩種風味的雞肉,簡單工廠並不能很好的實現。
對於這兩個問題,雖然可以在簡單工廠中加入多種xxxbread和xxxchicken 來解決,但是會產生很多問題!
分析: 對於問題一,假設第n個商店分別需要n_bread和n_chicken,那麼你需要在簡單工廠里加入2*n個條件語句,但是,這2*n個語句裡,其實只有2個是對其對應的商店有效的,其他的都是累贅!
對於問題二, 假如有n種食物,m種口味,那就是m*n個條件語句,對某個商店來說,有用的其實只有m1*n1個,仍然是有很多冗餘程式碼!
細心的讀者會發現,問題一可以看做問題二的子問題,並且都指向了程式碼的複用性!雖然簡單工廠可以複用,但效率太低了!
針對問題一,我們可以將那個具有2*n個條件語句的簡單工廠分成n個工廠,與商店一一對應,這樣解決了效率問題(不同的商店呼叫不同的工廠),但是,每個工廠類其實只為對應的商店服務,也就是說,每個工廠類都不需要複用卻被我們獨立開來!在前文提到過,工廠模式的目的是將物件的建立進行封裝,那麼能不能將這種封裝放在“特殊”的地方呢?當然能!工廠方法模式就是將其放到子類上!
工廠方法模式:定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類。
方法就是將物件建立部分宣告為抽象方法,交給子類去實現,如下:
abstract class Store { public Food orderFood(String type) { Food food = creatFood(type); food.prepare(); food.cut(); food.box(); return food; } public abstract Food creatFood(String type); //抽象方法,父類並不知道具體的物件型別,這將由子類決定 }
工廠方法模式相比簡單工廠更具有彈性,可以變更正在建立的產品,但是它也放棄了複用性!那怎麼能夠既保有彈性又能實現複用呢(這正是問題二所面臨的問題)?
不用多說,這個自然就是我們的抽象工廠模式,先看看定義吧!
抽象工廠模式:提供一個介面,用於建立相關或依賴物件的家族,而不需要明確指定具體類。
如下:
interface abstract_Factory { public Food creatBread(); public Food creatChicken(); }
做兩個實現類,如河北工廠和河南工廠,分別提供河北風味的麵包,雞肉和河南風味的麵包,雞肉,如下:
河北工廠
——————————————
class Hebei_Factory implements abstract_Factory { @Override public Food creatBread() { // TODO Auto-generated method stub return new Hebei_bread(); } @Override public Food creatChicken() { // TODO Auto-generated method stub return new Hebei_chicken(); } }
河南工廠
——————————————
class Henan_Factory implements abstract_Factory { @Override public Food creatBread() { // TODO Auto-generated method stub return new Henan_bread(); } @Override public Food creatChicken() { // TODO Auto-generated method stub return new Henan_chicken(); } }
相應的商店及執行程式碼
——————————————
class abstract_Factory_Story { Food food; public Food orderFood(String type,abstract_Factory factory) { if("bread".equals(type)){ food = factory.creatBread(); } else if("chicken".equals(type)) { food = factory.creatChicken(); } food.prepare(); food.cut(); food.box(); return food; } public static void main(String[] args) { abstract_Factory_Story afs=new abstract_Factory_Story(); afs.orderFood("bread", new Hebei_Factory()); afs.orderFood("chicken", new Henan_Factory()); } }
執行結果
——————————————
Hebei_bread:prepare............ Hebei_bread:cutting............ Hebei_bread:boxed............ Henan_chicken:prepare............ Henan_chicken:cutting............ Henan_chicken:boxed............
可以看出,執行時我們只要傳入不同的工廠,就能得到不同風味的食物,各個工廠子類也能複用,在商店類中並不依賴具體型別(food是所有食物的超類),能夠輕易的進行擴充套件而不用修改程式碼(type的判斷放在工廠中會更好)。
總結
縱覽三種設計模式,可以發現簡單工廠和工廠方法都可以看做抽象工廠的子模式,抽象工廠本身就是工廠方法組合而成(將物件的建立延遲到子工廠),而相應的每個子工廠,也都可以看做是一個簡單工廠,只不過在抽象工廠裡,運用了面對介面/超類程式設計的方法將商店類與子工廠具體型別解耦,使之更具有彈性。在很多情況下,簡單工廠和工廠方法都能很好的替代抽象工廠,例如,在不需要複用的物件建立封裝時,工廠方法比抽象工廠更合適,在建立物件的型別相對確定時(不需要彈性),用簡單工廠也能勝任。
本文連結:http://www.codeceo.com/article/java-factory-pattern.html
本文作者:碼農網 – 魯阿皓
[ 原創作品,轉載必須在正文中標註並保留原文連結和作者等資訊。]
相關文章
- 設計模式之工廠模式!深入解析簡單工廠模式,工廠方法模式和抽象工廠模式設計模式抽象
- 設計模式-簡單工廠、工廠方法模式、抽象工廠模式設計模式抽象
- Java 設計模式之工廠方法模式與抽象工廠模式Java設計模式抽象
- 簡單工廠模式和抽象工廠模式模式抽象
- 無廢話設計模式(1)--簡單工廠、工廠方法、抽象工廠設計模式抽象
- 一篇搞定工廠模式【簡單工廠、工廠方法模式、抽象工廠模式】模式抽象
- C# 設計模式(1)——簡單工廠模式、工廠模式、抽象工廠模式C#設計模式抽象
- 簡單工廠模式、工廠方法模式和抽象工廠模式有何區別?模式抽象
- 簡單工廠模式、工廠模式、抽象工廠模式比較模式抽象
- 設計模式學習筆記(三)簡單工廠、工廠方法和抽象工廠之間的區別設計模式筆記抽象
- 建立型:工廠模式-工廠方法、抽象工廠模式抽象
- 工廠模式之簡單工廠模式模式
- java設計模式–抽象工廠模式Java設計模式抽象
- Java設計模式-抽象工廠模式Java設計模式抽象
- Java常用設計模式之抽象工廠模式Java設計模式抽象
- 設計模式學習(二)工廠模式——抽象工廠模式設計模式抽象
- 設計模式 - 抽象工廠設計模式抽象
- 設計模式----抽象工廠設計模式抽象
- 設計模式 – 抽象工廠設計模式抽象
- JAVA設計模式 3【建立型】理解工廠模式與抽象工廠模式Java設計模式抽象
- Java設計模式學習筆記——工廠模式與抽象工廠模式Java設計模式筆記抽象
- java設計模式-簡單工廠模式Java設計模式
- Java常用設計模式之簡單工廠模式Java設計模式
- 設計模式之簡單工廠模式設計模式
- 設計模式(三)抽象工廠方法模式設計模式抽象
- 設計模式-工廠模式二(工廠方法模式)設計模式
- java 抽象工廠模式Java抽象模式
- 設計模式 —— 抽象工廠模式設計模式抽象
- 設計模式-抽象工廠模式設計模式抽象
- 設計模式——抽象工廠模式設計模式抽象
- golang設計模式之抽象工廠模式Golang設計模式抽象
- 設計模式系列之「抽象工廠模式」設計模式抽象
- Java設計模式之工廠方法模式Java設計模式
- Python 實現工廠模式、抽象工廠,單例模式Python模式抽象單例
- 【Java】簡單工廠模式、工廠模式、介面卡模式Java模式
- 設計模式----簡單工廠設計模式
- 工廠模式(簡單工廠模式)快速理解模式
- 建立型:工廠模式-簡單工廠模式
- 設計模式 - 簡單工廠模式設計模式