为了面向接口编程,而不是面向实现编程,所以此时我么就不能再直接使用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()类,决定实际制造出的披萨是什么。简单工厂的做法,可以将对象创建封
装起来,但是简单工厂不具备工厂方法的弹性,因为简单工程不能变更正在创建的产品。
未完待续......