以前基於簡單工廠的披薩店系統運行良好,那麼繼續進行拓展。java
因爲披薩店經營有成,以致於你們都但願自家附近有加盟店出現,身爲加盟公司的經營者,也就是PizzaStore對象,天然但願確保加盟店運行的質量,因此但願這些店都使用PizzaStore中通過時間考驗的代碼。框架
可是區域的差別不能視而不見,因爲加盟店的地理位置不一樣(比方說紐約店、芝加哥店、加州店),所使用的披薩也不一樣。ide
利用SimplePizzaFactory,修改它,寫出三種不一樣的工廠,分別是NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory,那麼各地加盟店都有合適的工廠可使用,這是一種作法。spa
在推廣SimpleFactory時,你發現加盟店的確是採用你的工廠建立比薩,可是其餘部分,卻開始採用他們自創的流程。烘烤的作法有些差別、不要切片、使用其餘廠商的盒子等等。設計
換句話說,加盟店只使用了工廠建立Pizza對象,而後不去調用Pizza對象的prepare()、bake()、cut()、box()方法。code
有個作法可讓比薩製做活動侷限於PizzaStore類,而同時又能讓這些加盟店依然能夠自由的只作該地區的披薩。對象
所要作的事情就是把createPizza()方法放回到PizzaStore中,不過要把它設置稱「抽象方法」,而後爲每一個區域風味建立一個PizzaStore的子類。繼承
首先,先看看如何修改PizzaStore類:ip
/** * 這裏一個披薩店的抽象類。 * */ public abstract class PizzaStore { /** * 訂購披薩的方法,返回一個披薩餅對象。 * */ public Pizza orderPizza(String type) { // 經過披薩工廠建立披薩。 Pizza pizza = createPizza(type); // 擀麪上料、烘烤、切片、裝盒。 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } /** * 根據披薩類型建立指定的披薩對象。 * */ abstract Pizza createPizza(String type); }
如今已經有一個PizzaStore做爲超類,讓每一個地區的加盟店都建立一個PizzaStore子類(NYPizzaStore、ChicagoPizzaStore、CaliforniaPizzaStore),每一個子類各自決定如何製造披薩。讓咱們看看這要如何進行。ci
各個區域比薩店之間的差別在於它們製做比薩時的習慣(紐約比薩的餅薄,芝加哥比薩的餅厚等),咱們如今讓createPizza()可以應對這些變化。
作法如上圖所示,讓PizzaStore的子類負責定義本身的createPizza()方法,因此咱們會獲得一些PizzaStore具體的子類,每一個子類都有本身的比薩實體生成方式,而仍然適合PizzaStore框架,餅使用已經寫好的orderPizza方法()。下面看用代碼如何實現:
public class NYStylePizzaStore extends PizzaStore { @Override Pizza createPizza(String type) { Pizza pizza; // 經過類型返回指定的披薩,但這些披薩都是紐約風味的。 if ("cheese".equals(type)) { pizza = new NYStyleCheesePizza(); } else if ("pepperoni".equals(type)) { pizza = new NYStylePepperoniPizza(); } else if ("clam".equals(type)) { pizza = new NYStyleClamPizza(); } else if ("veggie".equals(type)) { pizza = new NYStyleVeggiePizza(); } else { return null; } return pizza; } }
public class ChicagoStylePizzaFactory extends PizzaStore { @Override Pizza createPizza(String type) { Pizza pizza; // 經過類型返回指定的披薩,但這些披薩都是芝加哥風味的。 if ("cheese".equals(type)) { pizza = new ChicagoStyleCheesePizza(); } else if ("pepperoni".equals(type)) { pizza = new ChicagoStylePepperoniPizza(); } else if ("clam".equals(type)) { pizza = new ChicagoStyleClamPizza(); } else if ("veggie".equals(type)) { pizza = new ChicagoStyleVeggiePizza(); } else { return null; } return pizza; } }
本來是一個對象負責全部具體類的實例化,如今經過對PizzaStore作一些小轉變,變成由一羣子類來負責實例化。讓咱們看的更仔細些:
PizzaStore nyStylePizzaStore = new NYStylePizzaStore();
1.創建一個NYStylePizzaStore的實例;
Pizza nyPizza = nyStylePizzaStore.orderPizza("veggie");
2.調用NYStylePizzaStore實例的orderPizza()方法,傳遞參數veggie,是告訴紐約披薩店我須要一個素食披薩(固然是紐約風格的素食比薩)。
Pizza pizza = createPizza(type);
3.orderPizza()方法去調用工廠方法——createPizza(),並將type傳遞給它。他返回一個紐約風格的素質比薩。
pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box();
4.披薩店對比薩進行處理,返回給客戶。無論那個地區的披薩店,都要進行這些處理,沒有特別的,這樣,以前所說的不進行切片,使用其餘披薩店的盒子的問題就解決了!
全部工廠模式都用來封裝對象的建立,工廠方法模式(Factory Method Pattern)經過讓子類決定該建立的對象是什麼,來達到將對象建立的過程封裝的目的。
工廠方法模式可以封裝具體類型的實例化。看看下面的類圖:
他們看起來很相似,差異在於,在工廠方法中,返回比薩的類是子類(實現了PizzaStore的類)。具體解釋一下,子類的確看起來像是一個簡單工廠。
差異在於簡單工廠會把所有的事情都作好,在一個地方都處理完了。然而工廠方法倒是建立一個框架,讓子類決定要如何實現。比方說,在工廠方法中,orderPizza()方法提供了通常的框架,以便建立比薩,orderPizza()方法一來工廠方法建立的具體類,餅製造出實際的比薩。可經過繼承PizzaStore類,決定實際製造出的披薩是什麼。
而簡單工廠的作法,能夠將對象的建立封裝起來,可是簡單工廠不具有工廠方法的彈性,由於簡單工廠不能變動正在建立的產品。
有一個OO設計原則就正式闡明瞭這一點:這個原則甚至還有一個又響亮又正式的名稱:「依賴倒置原則」(Dependency Inversion Principle)。
3通則以下:
設計原則
要依賴抽象,不要依賴具體類。
下面的方針,能幫你避免在OO設計中違反依賴倒置原則:
可是,徹底遵照這些彷佛也不太可能,正如同許多原則同樣,應該儘可能去達到這個原則,而不是隨時都要遵循這個原則。
以上即是工廠方法的一些知識。