浅析设计模式(二)——工厂方法模式

工厂方法模式(Factory-Method,创建型模式)

本文的结构:

一、工厂方法模式的定义

  定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延迟到子类。

  从工厂方法的实现来看,它通过继承来实现,委托子类把创建对象的方法具体化,通常用于创建单个产品

  上一篇【浅析设计模式(四)——创建型模式之Simple-Factory(简单工厂方法,非设计模式)】中介绍的简单工厂方法,虽然已经对变化的部分进行了封装,但是这里只由一个对象负责所有的具体类的实例化,因此每次有新增对象类型时,都需要改变工厂的源码进行扩展。

  如果把实例化部分(即上面创建对象的createPizza方法)进行抽象,而且挪到PizzaStore(改为抽象类,即由抽象类定义上层接口)里面,然后由子类负责具体实现,那就可以使用一群子类来负责实例化了,而不用改变原有的子类实现及其实例化方式,比较容易进行扩展,当然,缺点就是需要维护一群子类,每次有新的类型时,在不修改原有实现的基础上,只能通过新增子类来进行实现;另外一点就是需要在运行时根据实际情况进行选择和确认具体类。简单工厂方法可以看成是工厂方法模式退化后的一种特例,即在确定需要实例化的对象基本不会变化、而且可控的情况下,将抽象的工厂方法与具体的工厂方法进行合并,始终由单一的具体工厂直接负责对象的实例化。

二、工厂方法模式的参与者及其角色

1. Product

  • 定义工厂方法要创建的对象的接口

2. ConcreteProduct

  • 实现Product接口,即具体的对象

3. Creator

  • 声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,他返回一个缺省的ConcreteProduct对象。

4. ConcreteCreator

  • 重定义工厂方法以返回一个ConcreteProduct对象。

三、工厂方法模式的类图 

四、工厂方法模式的示例

1. Creator:这个是工厂方法的上层接口,定义了创建对象的接口方法,也即对创建对象的方法进行了抽象化。

  这里还是从创建Pizza开涮。可以看出与简单工厂方法的差别,这里又把创建对象的方法搬回来了,只是抽象化了,没有具体实现,目的是要让子类类确认实例化的具体实现。其他的流程还是可以保持一致的。

 1 /**
 2  * This is the factory.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public abstract class PizzaStore {
 8     public abstract Pizza createPizza(String item);
 9      
10     public Pizza orderPizza(String type) {
11         Pizza pizza = createPizza(type);
12         System.out.println("--- Making a " + pizza.getName() + " ---");
13         pizza.prepare();
14         pizza.bake();
15         pizza.cut();
16         pizza.box();
17         return pizza;
18     }
19 }

 

2. ConcreteCreator:Creator的实现类,在这些实现子类中进行了具体的实现,也即实际创建对象的动作在这里发生。

实现类1:纽约风味的PizzaStore

 1 /**
 2  * This is the concrete factory-method.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public class NYPizzaStore extends PizzaStore {
 8 
 9     // Here is the concrete creator.
10     @Override
11     public Pizza createPizza(String item) {
12         if (item.equals("cheese")) {
13             return new NYStyleCheesePizza();
14         } else if (item.equals("veggie")) {
15             return new NYStyleVeggiePizza();
16         } else if (item.equals("clam")) {
17             return new NYStyleClamPizza();
18         } else if (item.equals("pepperoni")) {
19             return new NYStylePepperoniPizza();
20         } else
21             return null;
22     }
23 
24 }

 

实现类2:芝加哥风味的PizzaStore

 1 /**
 2  * This is the concrete factory-method.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public class ChicagoPizzaStore extends PizzaStore {
 8 
 9     // Here is the concrete creator.
10     @Override
11     public Pizza createPizza(String item) {
12         if (item.equals("cheese")) {
13             return new ChicagoStyleCheesePizza();
14         } else if (item.equals("veggie")) {
15             return new ChicagoStyleVeggiePizza();
16         } else if (item.equals("clam")) {
17             return new ChicagoStyleClamPizza();
18         } else if (item.equals("pepperoni")) {
19             return new ChicagoStylePepperoniPizza();
20         } else
21             return null;
22     }
23 
24 }

 

当然还可以添加南加州风味、洛杉矶风味等等的PizzaStore。

3. Product:需要创建的对象的父类。

  实际上,要创建的是一类对象,并不是单纯的某一个对象,因此,这里的抽象化也是很有必要的,而且后续的维护、扩展等也是基于抽象类来开展,进行实际的定制化、具体化。

 1 import java.util.ArrayList;
 2 
 3 /**
 4  * This is the abstract product.
 5  * <p>
 6  * Reference : Head-First-Design-Patterns
 7  *
 8  */
 9 public abstract class Pizza {
10     String name;
11     String dough;
12     String sauce;
13     ArrayList<String> toppings = new ArrayList<String>();
14  
15     void prepare() {
16         System.out.println("Prepare " + name);
17         System.out.println("Tossing dough...");
18         System.out.println("Adding sauce...");
19         System.out.println("Adding toppings: ");
20         for (String topping : toppings) {
21             System.out.println("   " + topping);
22         }
23     }
24   
25     void bake() {
26         System.out.println("Bake for 25 minutes at 350");
27     }
28  
29     void cut() {
30         System.out.println("Cut the pizza into diagonal slices");
31     }
32   
33     void box() {
34         System.out.println("Place pizza in official PizzaStore box");
35     }
36  
37     public String getName() {
38         return name;
39     }
40 
41     public String toString() {
42         StringBuffer display = new StringBuffer();
43         display.append("---- " + name + " ----\n");
44         display.append(dough + "\n");
45         display.append(sauce + "\n");
46         for (String topping : toppings) {
47             display.append(topping + "\n");
48         }
49         return display.toString();
50     }
51 }

 

4. ConcreteProduct:需要创建的具体对象,后续需要扩展新的对象,实现Pizza类即可。

示例1:

 1 /**
 2  * This is the concrete product.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public class NYStyleCheesePizza extends Pizza{
 8     public NYStyleCheesePizza() { 
 9         name = "NY Style Sauce and Cheese Pizza";
10         dough = "Thin Crust Dough";
11         sauce = "Marinara Sauce";
12  
13         toppings.add("Grated Reggiano Cheese");
14     }
15 }

 示例2:

 1 /**
 2  * This is the concrete product.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public class ChicagoStyleCheesePizza extends Pizza{
 8     public ChicagoStyleCheesePizza() { 
 9         name = "Chicago Style Deep Dish Cheese Pizza";
10         dough = "Extra Thick Crust Dough";
11         sauce = "Plum Tomato Sauce";
12  
13         toppings.add("Shredded Mozzarella Cheese");
14     }
15  
16     void cut() {
17         System.out.println("Cutting the pizza into square slices");
18     }
19 }

 其他的就省略了,具体可看后面的参考。。。。

5. 测试

  主要是使用上面的具体PizzaStore来创建各类Pizza。

 1 /**
 2  * This is the test-main.
 3  * <p>
 4  * Reference : Head-First-Design-Patterns
 5  *
 6  */
 7 public class PizzaTestApp {
 8     public static void main(String[] args) {
 9         
10         //2 concrete factory
11         PizzaStore nyStore = new NYPizzaStore();
12         PizzaStore chicagoStore = new ChicagoPizzaStore();
13 
14         Pizza pizza = nyStore.orderPizza("cheese");
15         System.out.println("Ethan ordered a " + pizza.getName() + "\n");
16 
17         pizza = chicagoStore.orderPizza("cheese");
18         System.out.println("Joel ordered a " + pizza.getName() + "\n");
19 
20         pizza = nyStore.orderPizza("clam");
21         System.out.println("Ethan ordered a " + pizza.getName() + "\n");
22 
23         pizza = chicagoStore.orderPizza("clam");
24         System.out.println("Joel ordered a " + pizza.getName() + "\n");
25 
26         pizza = nyStore.orderPizza("pepperoni");
27         System.out.println("Ethan ordered a " + pizza.getName() + "\n");
28 
29         pizza = chicagoStore.orderPizza("pepperoni");
30         System.out.println("Joel ordered a " + pizza.getName() + "\n");
31 
32         pizza = nyStore.orderPizza("veggie");
33         System.out.println("Ethan ordered a " + pizza.getName() + "\n");
34 
35         pizza = chicagoStore.orderPizza("veggie");
36         System.out.println("Joel ordered a " + pizza.getName() + "\n");
37     }
38 }

 

五、参考

1、参考《Head First设计模式》和GoF《设计模式:可复用面向对象软件的基础》

2、代码可参考【github传送门】、UML类图参考【github传送门

posted @ 2018-06-04 22:00  心明谭  阅读(351)  评论(0编辑  收藏  举报