天天看點

設計模式入門——工廠模式(工廠方法)

背景:

Pizza店開始允許加盟,在推廣SimpleFactory時,你發現加盟店的缺采用了你的工廠建立pizza,但其他部分卻開始采用他們自創的流程,烘烤方法有差異,不需要切片,使用其他廠商的盒子。

我們想建立一個架構,把加盟店和建立比薩捆綁在一起又保持一定的彈性。

SimplePizzaFactory代碼,制作pizza的代碼綁在PizzaStore裡,這麼做沒有彈性(不能在制作Pizza的過程中,加入自己的方法)。

設計:

把createPizza()方法放回到PizzaStore中并設定為抽象方法,然後每個區域風味建立一個PizzaStore的子類。每一個繼承PizzaStore的子類都必須實作createPizza()方法,由各個子類決定如何制造Pizza。

實作:

// 定義為抽象類  讓每個域類型都繼承這個PizzaStore,每個子類格子決定如何制造pizza
public abstract class PizzaStore {
    // 聲明為final 防止被子類覆寫 
    public final Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    // 把工廠對象裝提到這個方法中 子類必須實作
    abstract Pizza createPizza(String type); 
}
           
// 由子類實作一個具體的Pizza
public class NYPizzaStore extends PizzaStore {
    Pizza createPizza(String item) {
        if("cheese".equals(item)){
            return new NYStyleCheesePizza();
        } else if("veggie".equals(item)){
            return new NYStyleVeggiePizza();
        } else if("pepperoni".equals(item)){
            return new NYStylePepperoniPizza();
        } else return null;
    }
}
           

例子:

  1.  Joel和Ethan分别執行個體化一個ChiagoPizzaStore類和NYPizzaStore
  2. 有了各自的PizzaStore後,Joel和Ethan分别調用了orderPizza()方法,并傳入喜歡的Pizza類型
  3. orderPizza()方法調用createPizza()建立Pizza,createPizza()會将建立好的Pizza傳回,
  4. orderPizza()并不知道真正建立的是哪一類Pizza,它隻知道是Pizza,然後将其準備,烘烤,切片,裝盒,派送。

總結:

工廠方法模式:定義了一個建立對象的接口,但由子類決定要執行個體化的類是哪一個,工廠方法讓類把執行個體化推遲到子類

PizzaStore類中orderPizza()方法實作了很多事情(準備、烘培、切片、裝盒等),但它不知道哪個子類将實際上制作Pizza,這就是解藕(decouple)。

當orderPizza()調用createPizza()時,某個Pizza店子類将負責建立Pizza。但是子類不是實時作出決定,從orderPizza()方法的角度來說,如果選擇在NYStylePizzaStore訂購Pizza,就由這個子類做決定。是以并非又子類世紀做決定,而是由顧客決定到哪家風味的Pizza店裡才決定了Pizza的風味。

工廠方法用來處理對象的建立,并将這樣的行為封裝在子類中。這個客戶程式中關于超類的代碼就和子類對象建立代碼解藕了。

// 工廠方法是抽象的,是以依賴子類去處理對象的建立
// 工廠方法将客戶(也就是超類中的代碼,如orderPizza())和實際建立具體産品的代碼分隔開來。
abstract Product factoryMethod(String type)
           

簡單工廠與工廠方法之間的差異:簡單工廠把全部的事情在一個地方全都處理完了,然而工廠方法卻是建立了一個架構,讓子類決定要如何實作。比如說,orderPizza()方法提供了一般的架構以便建立Pizza,orderPizza()方法依賴工廠方法建立具體類,并制造出實際的Pizza。而簡單的工廠的做法是将對象的建立封裝起來,它不具備工廠方法的彈性,因為簡單工廠不能變更正在建立的産品。

工廠方法的好處:将建立對象的代碼集中在一個對象或方法中,可以避免代碼中的重複,并且更友善以後的維護。這也意味着客戶在執行個體化對象時,隻會依賴于接口,而不是具體類。這讓代碼更有彈性,可以應對未來的拓展。