zoukankan      html  css  js  c++  java
  • 工厂模式——结语

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

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

     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的反射机制。

  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/yulinfeng/p/5851560.html
Copyright © 2011-2022 走看看