• 工厂模式——结语


    前面我们讲了三个工厂模式,都是万变不离其宗,利用工厂模式来实例化不同的对象,虽然可能会多写一些代码,但这会为程序系统带来更方便的扩展性和尽量小的修改。

    我们来从头回顾一下为什么要用工厂模式,实现一个计算器的程序,初级程序员可能立马分分钟就能写出代码来,例如:

     1 package day_4_summary;
     2 
     3 /**
     4  * 计算器
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public class Calc {
    10     public static void main(String[] args){
    11         double numA = 1;
    12         double numB = 2;
    13         String opt = "+";
    14         double result = 0;
    15         
    16         if (opt.equals("+")){
    17             result = numA + numB;
    18         }
    19         if (opt.equals("-")){
    20             result = numA - numB;
    21         }
    22         if (opt.equals("*")){
    23             result = numA * numB;
    24         }
    25         if (opt.equals("/")){
    26             result = numA / numB;  //我们这里暂不考虑除数为0的情况
    27         }
    28         
    29         System.out.println("result=" + result);
    30     }
    31 }

    几乎是20行的代码就实现了需求,但“合适”不呢?这种写法,是初学编程时C语言面向过程的编程方式,这种方式可能会伴随我们很久很久,就算学到了面向对象语言,这种思维方式也会很久很久挥之不去。4个if,要做4次判断,有人说那我用else if,我用switch不就可以了吗?

    面向对象编程不是用一门面向对象的语言来编程。

    面向对象编程,让我们可维护、可复用、可扩展,低耦合、高内聚,这些到底是什么呢?我们用面向对象的编程方法来实现这个计算器,并且使用用简单工厂模式。

    我们首先画出简单工厂模式的UML类图,把加减乘除抽象成一个运算类,这里就能做到了可复用,如果还有开方、乘方运算再实现运算类就可以了,这就是可扩展。

    抽象运算类:

     1 package day_4_summary;
     2 
     3 /**
     4  * 抽象运算类
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public abstract class AbstractOption {
    10     private double numA;
    11     private double numB;
    12     public double getNumA() {
    13         return numA;
    14     }
    15     public void setNumA(double numA) {
    16         this.numA = numA;
    17     }
    18     public double getNumB() {
    19         return numB;
    20     }
    21     public void setNumB(double numB) {
    22         this.numB = numB;
    23     }
    24     
    25     public abstract double getResult();
    26 }

    实现抽象运算类,只举加法:

     1 package day_4_summary;
     2 
     3 /**
     4  * 加法类
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public class OptionAdd extends AbstractOption {
    10 
    11     /* (non-Javadoc)
    12      * @see day_4_summary.AbstractOption#getResult()
    13      */
    14     @Override
    15     public double getResult() {
    16         
    17         return super.getNumA() + super.getNumB();
    18     }
    19 
    20 }

    工厂类,用来负责实例化具体对象:

    package day_4_summary;
    
    /**
     * 工厂类
     * @author turbo
     *
     * 2016年9月7日
     */
    public class OptionFactory {
        
        public static AbstractOption CreateOption(String opt){
            AbstractOption option = null;
            
            switch (opt) {
                case "+" :
                    option = new OptionAdd();
                    break;
                case "-" :
                    //创建减法运算符类
                    break;
                case "*" :
                    //创建乘法运算类
                    break;
                case "/" :
                    //创建除法运算类
                    break;
                default :
                    break;
            }
            
            return option;
        }
    }

    客户端:

     1 package day_4_summary;
     2 
     3 /**
     4  * 客户端
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public class Main {
    10 
    11     /**
    12      * @param args
    13      */
    14     public static void main(String[] args) {
    15         AbstractOption option = OptionFactory.CreateOption("+");
    16         double result = 0.0;
    17         option.setNumA(1);
    18         option.setNumB(2);
    19         result = option.getResult();
    20     }
    21 
    22 }

    这样我们就用简单工厂模式实现了一个计算器,比起面向过程的编程方式,这样是不是有点感觉了呢?我们想要加法,只需将“+”传递给工厂类让它帮我们实例化一个加法运算类即可,我们不用管它是如何实现的。其他人想用加法时,只需调用这个工厂类来实例化即可,我们把工厂类的接口提供给他,他不用去管是怎么实现的,他只管用,这不就是可复用吗?

    如果,我要增加一个开方运算,你要实现一个更复杂的运算,那我们俩都要同时去修改工厂类里的代码,这将使得代码的维护性变得很差,能不能提供给我们一个接口,让我们自己去实现我们想要做的运算呢?这个时候就得用工厂方法模式了。

    同样,我们首先画出UML类图:

    应该能明白了吧?如果要新增一个运算方式,我们只需实现操作类和实现工厂类即可,而不必在原有代码的基础上做修改。

    抽象运算类和加法类不变,还是和上面的代码一样,我们主要来看工厂类的变化,此时工厂类变成了一个接口。

     1 package day_4_summary;
     2 
     3 /**
     4  * 工厂接口类
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public interface IFactory {
    10     AbstractOption createOption();
    11 }

    接着实现加法工厂类,省去其他运算工厂类。

     1 package day_4_summary;
     2 
     3 /**
     4  * 加法工厂类
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public class OperationAddFactory implements IFactory {
    10 
    11     /* (non-Javadoc)
    12      * @see day_4_summary.IFactory#createOption()
    13      */
    14     @Override
    15     public AbstractOption createOption() {
    16 
    17         return new OptionAdd();
    18     }
    19 
    20 }

    客户端代码:

     1 package day_4_summary;
     2 
     3 /**
     4  * 客户端
     5  * @author turbo
     6  *
     7  * 2016年9月7日
     8  */
     9 public class Main {
    10 
    11     /**
    12      * @param args
    13      */
    14     public static void main(String[] args) {
    15         IFactory factory = new OperationAddFactory();
    16         AbstractOption option = factory.createOption();
    17         double result = 0.0;
    18         option.setNumA(1);
    19         option.setNumB(1);
    20         result = option.getResult();
    21         System.out.println(result);
    22     }
    23 
    24 }

    这两者主要的区别就是上面说的,如果要新增一个运算类,简单工厂模式我得要在原有代码基础上修改,如果是工厂方法模式,我只需再实现工厂接口类即可,而不用再原有代码上做修改。


    至于抽象工厂方法,上一篇说的比较详细,这里主要是对比简单工厂模式和工厂方法模式,掌握了工厂方法模式后,即会抽象工厂模式。在抽象工厂模式中利用反射机制,这个值得研究一下。在后续会仔细研究一下Java的反射机制。

  • 相关阅读:
    概率图模型课堂笔记:2.4 取样方法
    概率图模型课堂笔记:2.2 置信度传播
    2018秋季学期学习总结
    人生路上影响最大的三位老师
    抓老鼠啊~亏了还是赚了?
    币值转换
    自我介绍
    打印沙漏
    2019春第七周作业
    第六周编程总结
  • 原文地址:https://www.cnblogs.com/yulinfeng/p/5851560.html
Copyright © 2020-2023  润新知