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


    工厂方法模式(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 + " ----
    ");
    44         display.append(dough + "
    ");
    45         display.append(sauce + "
    ");
    46         for (String topping : toppings) {
    47             display.append(topping + "
    ");
    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() + "
    ");
    16 
    17         pizza = chicagoStore.orderPizza("cheese");
    18         System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    19 
    20         pizza = nyStore.orderPizza("clam");
    21         System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
    22 
    23         pizza = chicagoStore.orderPizza("clam");
    24         System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    25 
    26         pizza = nyStore.orderPizza("pepperoni");
    27         System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
    28 
    29         pizza = chicagoStore.orderPizza("pepperoni");
    30         System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    31 
    32         pizza = nyStore.orderPizza("veggie");
    33         System.out.println("Ethan ordered a " + pizza.getName() + "
    ");
    34 
    35         pizza = chicagoStore.orderPizza("veggie");
    36         System.out.println("Joel ordered a " + pizza.getName() + "
    ");
    37     }
    38 }

    五、参考

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

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

  • 相关阅读:
    Notepad++ 中如何将代码格式化
    JAVA 解析复杂的json字符串
    8. java操作mongodb——查询数据
    7.第一次使用java连接mongodb遇到的问题
    13. Intellij IDEA调试功能使用总结
    HttpClient4.5简单使用
    12.Intellij IDEA 添加jar包的三种方式
    11.IntelliJ IDEA详细配置和使用教程(适用于Java开发人员)
    10.Intellij IDEA svn的使用详解
    黑客攻克索尼影业,掌控了操作系统的未来
  • 原文地址:https://www.cnblogs.com/wpbxin/p/9071513.html
Copyright © 2020-2023  润新知