HeadFirst設計模式(四) - 工廠模式之2 - 工廠方法

加盟披薩店

    以前基於簡單工廠的披薩店系統運行良好,那麼繼續進行拓展。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設計中違反依賴倒置原則:

  • 變量不能夠持有具體類的引用;
  • 不要讓類派生自具體類;
  • 不要覆蓋基類中已實現的方法;

    可是,徹底遵照這些彷佛也不太可能,正如同許多原則同樣,應該儘可能去達到這個原則,而不是隨時都要遵循這個原則。

    以上即是工廠方法的一些知識。

相關文章
相關標籤/搜索