1. 程式人生 > >設計模式之工廠模式(二)

設計模式之工廠模式(二)

diagonal lam p 地址 加盟 tom 挨踢 類型 jpg 但是

之前已經帶大家稍微入門了工廠模式(即簡單工廠模式)的方法,沒看過的朋友可以移步去查看一番。設計模式之工廠模式(一)。今天我們繼續吃著披薩,學習著工廠模式的接下來部分吧。

加盟披薩店

我們先前的披薩店已經經營有成,擊敗了部分競爭者,接下來的計劃就是開加盟店。作為經營者,你肯定希望確保加盟店運營的質量,所以希望這些店都是用你那些經過時間考驗的代碼。

但是每個地方可能需要不同口味的披薩(比如A地區、B地區、C地區等),這就是開店地點以及該地區披薩美食家口味的影像。

如果利用先前的簡單工廠,那麽就是需要創建多個不同的工廠可以使用。代碼如下:

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("Veggie");

ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore nyStore = new PizzaStore(chicagoFactory);
nyStore.orderPizza("Veggie");

給披薩店使用的框架

在使用簡單工廠的時候,我們發現加盟店的確是采用工廠創建披薩,但是其他部分,卻開始采用自己的方式。有個做法可以讓披薩制作活動局限於PizzaStore類,而同時又能讓這些加盟店可以自由地制作該地區的風味。

所要做的事情呢,就是把之前createPizza()方法放回到PizzaStore中,不過不是單純的放回來,而是把它設置成抽象方法,然後每個區域創建一個PizzaStore的子類即可。.放出部分代碼來看看

public abstract class PizzaStore {
    public Pizza orderPizza(String type) {
        // 現在createPizza()方法從工廠對象中移回PizzaStore
        Pizza pizza = createPizza(type);
        ...
        return pizza;
    }
    
    // 現在把工廠對象移動到這個方法中
    abstract Pizza createPizza(String type);
}

現在上面這個就作為超類;讓每個域類型都繼承這個PizzaStore,每個子類各自決定如何制造披薩。

允許子類做決定

我們現在要讓createPizza()能夠應對各種變化創建正確種類的披薩。做法是讓PizzaStore的各個子類負責定義自己的createPizza()方法。所以,我們會得到一些PizzaStore具體的子類,每個子類都有自己的披薩變體,而仍然適合PizzaStore框架,並使用調試好的orderPizza()方法。
技術分享圖片;

這時候會有人肯定納悶了,PizzaStore的子類終究是子類,如何能做決定呢?關於這個方面,要從PizzaStore的orderPizza()方法觀點來看,此方法在抽象的PizzaStore內定義,但是只在子類中實現具體類型。

現在,更進一步地,orderPizza()方法對Pizza對象做了許多事情,但由於Pizza對象是抽象的,orderPizza()並不知道哪些實際的具體類參與進來了。換句話說,這就是解耦(decopule)。

當orderPizza()調用createPizza()時,就會由具體的披薩店來決定做哪一種披薩。那麽,子類是實時做出這樣的決定嗎?不是,但從orderPizza()角度來看,如果選擇在NYStylePizzaStore訂購披薩,就是由這個子類決定。

讓我們開一家披薩店吧

現在我們把加盟店開了。其實我們只需要繼承PizzaStore,然後提供createPizza()方法實現自己的披薩風味即可。比如紐約風味:

// NYPizzaStore擴展PizzaStore,所以擁有orderPizza方法(以及其他方法)
public class NYPizzaStore extends PizzaStore {

// createPizza()返回一個Pizza對象,由子類全權負責該實例化哪一個具體的Pizza
    Pizza createPizza(String item) {
        if (item.equals("cheese")) {
            return new NYStyleCheesePizza();
        } else if (item.equals("veggie")) {
            return new NYStyleVeggiePizza();
        } else if (item.equals("clam")) {
            return new NYStyleClamPizza();
        } else if (item.equals("pepperoni")) {
            return new NYStylePepperoniPizza();
        } else return null;
    }
}

工廠方法用來處理對象的創建,並將這樣的行為封裝在子類中。這樣,客戶程序中關於超類的代碼就和子類對象創建代碼解耦了。

如何利用披薩工廠方法訂購披薩

  1. 首先,需要取得披薩店的實例。A需要實例化一個ChicagoPizzaStore,而B需要一個NYPizzaStore
  2. 有了各自的PizzaStore,A和B分別調用orderPizza()方法,並傳入他們所喜愛的披薩類型
  3. orderPizza()調用createPizza()創建披薩。其中NYPizzaStore實例化的是紐約風味披薩,而ChicagoPizzaStore實例化的是芝加哥風味披薩。createPizza()會創建好的披薩當做返回值。
  4. orderPizza()並不知道真正創建的是哪一個披薩,只知道這是一個披薩,能夠被準備、被烘烤、被切片、被裝盒、然後提供給A和B

看看如何根據訂單生產這些披薩

  1. 先看看A的訂單,首先我們需要一個紐約披薩店:
// 建立一個NYPizzaStore的實例
PizzaStore nyPizzaStore = new NYPizzaStore();
  1. 現在有了一個店,可以下訂單了:
// 調用nyPizzaStore實例的orderPizza()方法
nyPizzaStore.orderPizza("cheese");
  1. orderPizza()方法於是調用cratePizza()方法
// 別忘了,工廠方法create-Pizza()是在子類中實現的。在這個例子中,他會返回紐約芝士披薩
Pizza pizza = createPizza("cheese");
  1. 最後,披薩必須經過下列的處理才算成功orderPizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

吃披薩咯

我們需要先有一個比薩,不然披薩店開起來了,結果沒有產品,豈不是很尷尬。

// 從一個抽象披薩類開始,所有的具體披薩都必須派生自這個類
public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList<String> toppings = new ArrayList<String>();
 
    void prepare() {
        System.out.println("Prepare " + name);
        System.out.println("Tossing dough...");
        System.out.println("Adding sauce...");
        System.out.println("Adding toppings: ");
        for (String topping : toppings) {
            System.out.println("   " + topping);
        }
    }
  
    void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }
 
    void cut() {
        System.out.println("Cut the pizza into diagonal slices");
    }
  
    void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }
 
    public String getName() {
        return name;
    }

    public String toString() {
        StringBuffer display = new StringBuffer();
        display.append("---- " + name + " ----\n");
        display.append(dough + "\n");
        display.append(sauce + "\n");
        for (String topping : toppings) {
            display.append(topping + "\n");
        }
        return display.toString();
    }
}

我們來定義一些具體的子類,在這裏,其實就是定義紐約和芝加哥風味的芝士披薩

public class NYStyleCheesePizza extends Pizza {

    public NYStyleCheesePizza() { 
        name = "NY Style Sauce and Cheese Pizza";
        dough = "Thin Crust Dough";
        sauce = "Marinara Sauce";
 
        toppings.add("Grated Reggiano Cheese");
    }
}
public class ChicagoStyleClamPizza extends Pizza {
    public ChicagoStyleClamPizza() {
        name = "Chicago Style Clam Pizza";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
 
        toppings.add("Shredded Mozzarella Cheese");
        toppings.add("Frozen Clams from Chesapeake Bay");
    }
 
    void cut() {
        System.out.println("Cutting the pizza into square slices");
    }
}

好了等久了吧,馬上來吃披薩了,這個時候剛好是下午4點左右,小編感覺已經餓的不行。

public class PizzaTestDrive {
 
    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();
 
        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza("clam");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
        pizza = chicagoStore.orderPizza("clam");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza("pepperoni");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
        pizza = chicagoStore.orderPizza("pepperoni");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");

        pizza = nyStore.orderPizza("veggie");
        System.out.println("Ethan ordered a " + pizza.getName() + "\n");
 
        pizza = chicagoStore.orderPizza("veggie");
        System.out.println("Joel ordered a " + pizza.getName() + "\n");
    }
}

好了,至此我們已經開了紐約和芝加哥披薩店,並已經愉快的制作和吃上了披薩,而且這是通過我們的工廠方法模式創建並得到的。

關於認識工廠方法模式,因為這篇我們已經通過代碼來了解了下,我將在下一篇進行解釋並進一步認識這個模式,請大家敬請期待吧。

PS:因為工廠模式涉及的篇幅較大,幾篇文章可能存在不合理的銜接,小編會盡快輸出全部文章,讓大家能一次了解,在此給大家道個歉。

GitHub地址 HeadFirstDesign

愛生活,愛學習,愛感悟,愛挨踢

技術分享圖片

設計模式之工廠模式(二)