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