设计模式之工厂模式(上篇)

懵懂的女人 提交于 2019-11-26 12:48:54

为了面向接口编程,而不是面向实现编程,所以此时我么就不能再直接使用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 }

 

结果展示(部分结果)

 

此段代码地址:

          https://github.com/Stray-Kite/Design-Pattern/tree/master/src/headfirst/designpatterns/factory/pizzafm

好了,现在然我们看一下工厂模式的定义吧!

工厂模式:定义一个创建对象的接口,但由子类决定要实例化的是哪一个。工厂方法让类把

实例化推迟到了子类。

重点:简单工厂和工厂方法的区别:

                 子类的确看起来很像简单工厂。简单工程把全部的事情,在一个地方都处理完了,然而工厂方

          法却是创建了一个框架,让子类决定要如何实现。比方说,在工厂方法中,orderPizza()方法提供了

          一个一般的框架,以便创建披萨,orderPizza()方法依赖工厂方法创建具体类,并制造出实际的披萨

          。可通过继承PizzaStore()类,决定实际制造出的披萨是什么。简单工厂的做法,可以将对象创建封

          装起来,但是简单工厂不具备工厂方法的弹性,因为简单工程不能变更正在创建的产品。

未完待续......

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!