• 简说设计模式——工厂方法模式


    一、什么是工厂方法模式

      工厂二字想必大家都不陌生,工厂就是用来建造东西的,我们市面上买的东西比如水杯、玩具、汽车等等都是从工厂生产的,那我们需不需要知道它们是如何生产出来的呢?当然不需要,商家从工厂中直接提货,我们就可以购买了,完全不知道它是如何生产的,这就是工厂方法模式。

           工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式使一个类的实例化延迟到其子类。UML结构图如下:

           其中,Product定义工厂方法所创建的对象的接口;Creator声明工厂方法,并返回一个Product类型的对象;ConcreteProduct是具体的产品,实现了Product接口;ConcreteCreteCreator重定义工厂方法,返回一个ConcreteProduct实例。

        1. Product类

           下述代码是一个抽象产品类,具体的产品类可以有多个,都继承于抽象产品类。
    1 public abstract class Product {
    2     //产品类的公共方法
    3     public void method1() {
    4         //业务逻辑处理
    5     }
    6     //抽象方法
    7     public abstract void method2();
    8 }

        2. ConcreteProduct类

           具体产品类,可创建多个。

    1 public class ConcreteProduct1 extends Product {
    2 
    3     @Override
    4     public void method2() {
    5         // 业务逻辑处理
    6     }
    7 
    8 }

        3. Creator类

        下述代码是一个抽象工厂类,主要负责定义产品对象的产生。

    1 public abstract class Creator {
    2 
    3     //创建一个产品对象,参数自行设置
    4     public abstract <T extends Product> T createProduct(Class<T> c);
    5     
    6 }

        4. ConcreteCreator类

           具体如何产生一个产品的对象,是由具体的工厂类实现的。

     1 public class ConcreteCreator extends Creator {
     2 
     3     @Override
     4     public <T extends Product> T createProduct(Class<T> c) {
     5         Product product = null;
     6         try {
     7             product = (Product) Class.forName(c.getName()).newInstance();
     8         } catch (Exception e) {
     9             // TODO: handle exception
    10         }
    11         return (T) product;
    12     }
    13 
    14 }

           调用时就可以使用我们创建的工厂来完成相应的操作了,如下:

    1 Creator creator = new ConcreteCreator();
    2 creator.createProduct(ConcreteProduct1.class);

    二、工厂方法模式的应用

        1. 何时使用

    • 不同条件下创建不用实例时。方法是让子类实现工厂接口。

        2. 优点

    • 良好的封装性,代码结构清晰。如一个调用者想创建一个对象,只需要知道其名称即可,降低了模块间的耦合。
    • 扩展性好。如果想增加一个产品,只需扩展一个工厂类即可。
    • 屏蔽产品类。调用者只关心产品的接口。
    • 典型的解耦框架。

        3. 缺点

    • 每增加一个产品,就需要增加一个产品工厂的类,增加了系统的复杂度。

        4. 使用场景

    • 需要生成对象的地方。
    • 需要灵活的、可扩展的框架时。
    • 数据库访问,数据库可能变化时。

        5. 应用实例

    • 需要一辆汽车,直接从工厂里面提货,不用去管这辆车是怎么做出来的。
    • Hibernate换数据库只需换方言和驱动即可。
    • 简单计算器的实现。

    三、简单工厂模式的实现

           在看工厂方法模式的实现之前,我们先来了解一下简单工厂模式。简单工厂模式就是用一个单独的类来做创造实例的过程,这个类就是工厂。

           我们以简单计算器的实现为例,这里只给出部分代码用于与工厂方法模式做对比。UML图如下:

           工厂类如下:

     1 public class OperationFactory {
     2     public static Operation createOperate(String operate) {
     3         Operation oper = null;
     4         switch(operate) {
     5             case "+":
     6                 oper = new OperationAdd();
     7                 break;
     8             case "-":
     9                 oper = new OperationSub();
    10                 break;
    11             case "*":
    12                 oper = new OperationMul();
    13                 break;
    14             case "/":
    15                 oper = new OperationDiv();
    16                 break;
    17         }
    18         return oper;
    19     }
    20 }

           其余类参考下方工厂方法模式。

    四、工厂方法模式的实现

           现在再对这个计算器用工厂方法模式进行编写,看一下两种模式间有什么区别。UML图如下:

        1. 运算类

     1 public class Operation {
     2     
     3     protected double numberA = 0;
     4     protected double numberB = 0;
     5     
     6     public double getNumberA() {
     7         return numberA;
     8     }
     9     public void setNumberA(double numberA) {
    10         this.numberA = numberA;
    11     }
    12     public double getNumberB() {
    13         return numberB;
    14     }
    15     public void setNumberB(double numberB) {
    16         this.numberB = numberB;
    17     }
    18 
    19     public double getResult() {
    20         double result = 0;
    21         return result;
    22     }
    23 }

        2. 工厂接口

    1 public interface IFactory {
    2     Operation createOperation();
    3 }

        3. 具体运算类

           这里以加减乘除四种运算为例,需要四个实现类,都继承运算类。

     1 public class OperationAdd extends Operation {
     2 
     3     @Override
     4     public double getResult() {
     5         double result = 0;
     6         result = numberA + numberB;
     7         
     8         return result;
     9     }
    10     
    11 }

           其余三个省略。

        4. 运算工厂

           有四个运算类,就需要四个运算工厂,都实现了工厂接口。
    1 public class AddFactory implements IFactory {
    2 
    3     @Override
    4     public Operation createOperation() {
    5         return new OperationAdd();
    6     }
    7 
    8 }
           其余三个省略。

        5. Client客户端

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         IFactory oFactory = new AddFactory();
     5 //        IFactory oFactory = new SubFactory();
     6 //        IFactory oFactory = new MulFactory();
     7 //        IFactory oFactory = new DivFactory();
     8         
     9         Operation operation = oFactory.createOperation();
    10         
    11         operation.numberA = 5;
    12         operation.numberB = 7;
    13         
    14         double result = operation.getResult();
    15         System.out.println(result);
    16     }
    17     
    18 }

           如上述代码,为加法的运算,若需要进行其他运算,只需实现该接口的其他实现类(如注释所示)。运行结果如下:

           实现加法工厂,进行加法运算,5+7的结果为12。

    五、简单工厂模式与工厂方法模式的区别

           如果现在需要增加其他运算,比如取余。简单工厂模式需要在添加case分支条件,修改了原有的类,违背了开闭原则;而工厂方法模式只需再新加个取余类和取余工厂,然后对客户端进行修改即可。

           简单工厂模式最大的优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对与客户端来说,去除了与具体产品的依赖。为了弥补他违背了开闭原则,于是就有了工厂方法模式,根据依赖倒转原则,把工厂类抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。

           其实工厂方法模式还存在一个问题,就是客户端需要决定实例化哪一个工厂来实现运算类,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。对于这个问题,可以利用反射来解决(具体实例可参考抽象工厂模式中的反射实例)。

           源码地址:https://gitee.com/adamjiangwh/GoF

  • 相关阅读:
    hash表及带注释插头dp
    NOIP模拟测试9「随·单·题」
    静态点分治总结
    NOIP模拟测试8「匹配·回家」
    NOIP模拟测试8「寿司」
    「PKUWC2018」Slay the Spire
    矩阵快速幂总结
    SQL中的object_id函数
    SQL数据库Replace的用法
    SQL批量提交修改业务
  • 原文地址:https://www.cnblogs.com/adamjwh/p/9033553.html
Copyright © 2020-2023  润新知