欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-29 10:11:42
为了面向接口编程,而不是面向实现编程,所以此时我么就不能再直接使用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 }

 

结果展示(部分结果)

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

 

此段代码地址:

          https://github.com/stray-kite/design-pattern/tree/master/src/headfirst/designpatterns/factory/pizzafm

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

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

实例化推迟到了子类。

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

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

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

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

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

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

未完待续......