之前已經帶大家稍微入門了工廠模式(即簡單工廠模式)的方法,沒看過的朋友可以移步去檢視一番。設計模式之工廠模式(一)。今天我們繼續吃著披薩,學習著工廠模式的接下來部分吧。
加盟披薩店
我們先前的披薩店已經經營有成,擊敗了部分競爭者,接下來的計劃就是開加盟店。作為經營者,你肯定希望確保加盟店運營的質量,所以希望這些店都是用你那些經過時間考驗的程式碼。
但是每個地方可能需要不同口味的披薩(比如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;
}
}
複製程式碼
工廠方法用來處理物件的建立,並將這樣的行為封裝在子類中。這樣,客戶程式中關於超類的程式碼就和子類物件建立程式碼解耦了。
如何利用披薩工廠方法訂購披薩
- 首先,需要取得披薩店的例項。A需要例項化一個ChicagoPizzaStore,而B需要一個NYPizzaStore
- 有了各自的PizzaStore,A和B分別呼叫orderPizza()方法,並傳入他們所喜愛的披薩型別
- orderPizza()呼叫createPizza()建立披薩。其中NYPizzaStore例項化的是紐約風味披薩,而ChicagoPizzaStore例項化的是芝加哥風味披薩。createPizza()會建立好的披薩當做返回值。
- orderPizza()並不知道真正建立的是哪一個披薩,只知道這是一個披薩,能夠被準備、被烘烤、被切片、被裝盒、然後提供給A和B
看看如何根據訂單生產這些披薩
- 先看看A的訂單,首先我們需要一個紐約披薩店:
// 建立一個NYPizzaStore的例項
PizzaStore nyPizzaStore = new NYPizzaStore();
複製程式碼
- 現在有了一個店,可以下訂單了:
// 呼叫nyPizzaStore例項的orderPizza()方法
nyPizzaStore.orderPizza("cheese");
複製程式碼
- orderPizza()方法於是呼叫cratePizza()方法
// 別忘了,工廠方法create-Pizza()是在子類中實現的。在這個例子中,他會返回紐約芝士披薩
Pizza pizza = createPizza("cheese");
複製程式碼
- 最後,披薩必須經過下列的處理才算成功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