為了面向介面編程,而不是面向實現編程,所以此時我麽就不能再直接使用new了,因 為當看到“new”時,我們就會想到“具體”。 下麵來看一個例子,假如你有一個披薩店,你的代碼可能這麼寫: 但是此時你需要更多披薩類型,所以你就要修改代碼,如下所示: 但是此時由於產業競爭問題,你想加入一些其他口味的piz ...
為了面向介面編程,而不是面向實現編程,所以此時我麽就不能再直接使用new了,因
為當看到“new”時,我們就會想到“具體”。
下麵來看一個例子,假如你有一個披薩店,你的代碼可能這麼寫:
1 Pizza orderPizza(){ 2 Pizza pizza = new Pizza(); 3 4 pizza.prepare(); 5 pizza.bake(); 6 pizza.cut(); 7 pizza.box(); 8 9 return pizza; 10 }
但是此時你需要更多披薩類型,所以你就要修改代碼,如下所示:
1 Pizza orderPizza(String type){ 2 Pizza pizza = new Pizza(); 3 4 if (type.equals("cheese")) { 5 pizza = new CheesePizza(); 6 } else if (type.equals("pepperoni")) { 7 pizza = new PepperoniPizza(); 8 } else if (type.equals("clam")) { 9 pizza = new ClamPizza(); 10 } else if (type.equals("veggie")) { 11 pizza = new VeggiePizza(); 12 } 13 14 pizza.prepare(); 15 pizza.bake(); 16 pizza.cut(); 17 pizza.box(); 18 19 return pizza; 20 }
但是此時由於產業競爭問題,你想加入一些其他口味的pizza或者刪除某幾種pizza,那麼
你就不得不修改orderPizza(String type)里的4-12行,所以隨著時間的推移,這個類就必
須一改再改,這毫無疑問是不好的!所以我們現在來把創建對象的代碼封裝起來,如下所
示:
這時我們稱這個新對象(SimplePizzaFactory)為“工廠”,用來處理創建對象的細節。
現在讓我們創建一個簡單的披薩工廠:
先從工廠本身開始,封裝創建對象的代碼(SimplePizzaFactory.java):
1 public class SimplePizzaFactory { 2 public Pizza createPizza(String type) { 3 Pizza pizza = null; 4 5 if (type.equals("cheese")) { 6 pizza = new CheesePizza(); 7 } else if (type.equals("pepperoni")) { 8 pizza = new PepperoniPizza(); 9 } else if (type.equals("clam")) { 10 pizza = new ClamPizza(); 11 } else if (type.equals("veggie")) { 12 pizza = new VeggiePizza(); 13 } 14 return pizza; 15 } 16 }
重做PizzaStore(PizzaStore.java):
1 public class PizzaStore { 2 SimplePizzaFactory factory; 3 4 public PizzaStore(SimplePizzaFactory factory) { 5 this.factory = factory; 6 } 7 8 public Pizza orderPizza(String type) { 9 Pizza pizza; 10 11 pizza = factory.createPizza(type); 12 13 pizza.prepare(); 14 pizza.bake(); 15 pizza.cut(); 16 pizza.box(); 17 18 return pizza; 19 } 20 }
測試類(Main.java):
1 public class Main { 2 3 public static void main(String[] args) { 4 SimplePizzaFactory factory = new SimplePizzaFactory(); 5 PizzaStore store = new PizzaStore(factory); 6 7 Pizza pizza = store.orderPizza("cheese"); 8 System.out.println("We ordered a " + pizza.getName() + "\n"); 9 System.out.println(pizza); 10 11 pizza = store.orderPizza("veggie"); 12 System.out.println("We ordered a " + pizza.getName() + "\n"); 13 System.out.println(pizza); 14 } 15 }
結果展示:
好啦,這個示例完成了,這個其實叫做簡單工廠,他其實不是一個設計模式,而更像是一
種編程習慣。這裡只列舉了這個項目的關鍵代碼,至於這個簡單工廠的完整代碼,讀者可
到:https://github.com/Stray-Kite/Design-Pattern/tree/master/src/headfirst/designpatterns/factory/pizzas
下載。
好了,下載聊完了簡單工廠,那麼讓我們進入正題,聊一聊兩個重量級的模式,他們都是
工廠!
現在我們要建立幾個加盟店。
有了這個圖,你開始有一個想法啦,那就是:
1 NYPizzaFactory nyFactory = new NYPizzaFactory(); 2 PizzaStore nyStore = new PizzaStore(nyFactory); 3 nyStore.orderPizza("Veggie"); 4 5 ChicagePizzaFactory chicageFactory = new ChicagePizzaFactory(); 6 PizzaStore chicageStore = new PizzaStore(chicagoFactory); 7 chicagoStore.orderPizza("Veggie");
但是,你想要多一些質量控制:在推廣SimpleFactory時,你發現加盟店的確是採用你的工
廠創建披薩,但是其他部分,卻開始採用他們自創的流程:烘烤的做法有些差異、不要切片
、使用其他廠商的盒子。
再想想這個問題,你真的希望能夠建立一個框架,把加盟店和創建披薩捆綁在一起的同時又
保持一定的彈性。
所以開始使用框架啦:
首先,看看PizzaStore(PizzaStore.java)所做的改變;喔嚯,變成抽象的了,也就是把創
建對象的工作移交給子類做決定了:
1 public abstract class PizzaStore { 2 abstract Pizza createPizza(String item); 3 4 public Pizza orderPizza(String type) { 5 Pizza pizza = createPizza(type); 6 System.out.println("--- Making a " + pizza.getName() + " ---"); 7 pizza.prepare(); 8 pizza.bake(); 9 pizza.cut(); 10 pizza.box(); 11 return pizza; 12 } 13 }
接下來,輪到子類給PizzaStore做決定了!(NYPizzaStore.java和ChicagePizzaStore.java
,這是兩個披薩店):
1 public class ChicagoPizzaStore extends PizzaStore { 2 Pizza createPizza(String item) { 3 if (item.equals("cheese")) { 4 return new ChicagoStyleCheesePizza(); 5 } else if (item.equals("veggie")) { 6 return new ChicagoStyleVeggiePizza(); 7 } else if (item.equals("clam")) { 8 return new ChicagoStyleClamPizza(); 9 } else if (item.equals("pepperoni")) { 10 return new ChicagoStylePepperoniPizza(); 11 } else return null; 12 } 13 }
1 public class NYPizzaStore extends PizzaStore{ 2 Pizza createPizza(String item) { 3 if (item.equals("cheese")) { 4 return new NYStyleCheesePizza(); 5 } else if (item.equals("veggie")) { 6 return new NYStyleVeggiePizza(); 7 } else if (item.equals("clam")) { 8 return new NYStyleClamPizza(); 9 } else if (item.equals("pepperoni")) { 10 return new NYStylePepperoniPizza(); 11 } else return null; 12 } 13 }
差點忘記了,我們還得寫一個比薩本身(Pizza.java):
1 import java.util.ArrayList; 2 3 public abstract class Pizza { 4 String name; 5 String dough; 6 String sauce; 7 ArrayList<String> toppings = new ArrayList<String>(); 8 9 void prepare() { 10 System.out.println("Prepare " + name); 11 System.out.println("Tossing dough..."); 12 System.out.println("Adding sauce..."); 13 System.out.println("Adding toppings: "); 14 for (String topping : toppings) { 15 System.out.println(" " + topping); 16 } 17 } 18 19 void bake() { 20 System.out.println("Bake for 25 minutes at 350"); 21 } 22 23 void cut() { 24 System.out.println("Cut the pizza into diagonal slices"); 25 } 26 27 void box() { 28 System.out.println("Place pizza in official PizzaStore box"); 29 } 30 31 public String getName() { 32 return name; 33 } 34 35 public String toString() { 36 StringBuffer display = new StringBuffer(); 37 display.append("---- " + name + " ----\n"); 38 display.append(dough + "\n"); 39 display.append(sauce + "\n"); 40 for (String topping : toppings) { 41 display.append(topping + "\n"); 42 } 43 return display.toString(); 44 } 45 }
然後還剩下,一些具體的子類:定義兩個不同的店的芝士披薩
NYStyleCheesePizza.java:
1 public class NYStyleCheesePizza extends Pizza { 2 public NYStyleCheesePizza() { 3 name = "NY Style Sauce and Cheese Pizza"; 4 dough = "Thin Crust Dough"; 5 sauce = "Marinara Sauce"; 6 7 toppings.add("Grated Reggiano Cheese"); 8 } 9 }
ChicagoStyleCheesePizza.java:
1 public class ChicagoStyleCheesePizza extends Pizza { 2 public ChicagoStyleCheesePizza() { 3 name = "Chicago Style Deep Dish Cheese Pizza"; 4 dough = "Extra Thick Crust Dough"; 5 sauce = "Plum Tomato Sauce"; 6 7 toppings.add("Shredded Mozzarella Cheese"); 8 } 9 10 void cut() { 11 System.out.println("Cutting the pizza into square slices"); 12 } 13 }
最後來一組測試類(Main.java):
1 public class Main { 2 3 public static void main(String[] args) { 4 PizzaStore nyStore = new NYPizzaStore(); 5 PizzaStore chicagoStore = new ChicagoPizzaStore(); 6 7 Pizza pizza = nyStore.orderPizza("cheese"); 8 System.out.println("Ethan ordered a " + pizza.getName() + "\n"); 9 10 pizza = chicagoStore.orderPizza("cheese"); 11 System.out.println("Joel ordered a " + pizza.getName() + "\n"); 12 13 pizza = nyStore.orderPizza("clam"); 14 System.out.println("Ethan ordered a " + pizza.getName() + "\n"); 15 16 pizza = chicagoStore.orderPizza("clam"); 17 System.out.println("Joel ordered a " + pizza.getName() + "\n"); 18 19 pizza = nyStore.orderPizza("pepperoni"); 20 System.out.println("Ethan ordered a " + pizza.getName() + "\n"); 21 22 pizza = chicagoStore.orderPizza("pepperoni"); 23 System.out.println("Joel ordered a " + pizza.getName() + "\n"); 24 25 pizza = nyStore.orderPizza("veggie"); 26 System.out.println("Ethan ordered a " + pizza.getName() + "\n"); 27 28 pizza = chicagoStore.orderPizza("veggie"); 29 System.out.println("Joel ordered a " + pizza.getName() + "\n"); 30 } 31 }
結果展示(部分結果):
此段代碼地址:
好了,現在然我們看一下工廠模式的定義吧!
工廠模式:定義一個創建對象的介面,但由子類決定要實例化的是哪一個。工廠方法讓類把
實例化推遲到了子類。
重點:簡單工廠和工廠方法的區別:
子類的確看起來很像簡單工廠。簡單工程把全部的事情,在一個地方都處理完了,然而工廠方
法卻是創建了一個框架,讓子類決定要如何實現。比方說,在工廠方法中,orderPizza()方法提供了
一個一般的框架,以便創建披薩,orderPizza()方法依賴工廠方法創建具體類,並製造出實際的披薩
。可通過繼承PizzaStore()類,決定實際製造出的披薩是什麼。簡單工廠的做法,可以將對象創建封
裝起來,但是簡單工廠不具備工廠方法的彈性,因為簡單工程不能變更正在創建的產品。
未完待續......