zoukankan      html  css  js  c++  java
  • 简单工厂模式&工厂方法模式

    一、简单工厂模式

    软件设计的目标:可维护、可复用、可扩展、灵活性好!

    通过封装、继承、多态把程序的耦合度降低,使程序容易修改,并且易于复用。

    以一个简单的计算器程序(加减乘除)为例,实现该程序有多种方式:

    1. 在main方法里把计算器的逻辑写完;
    2. 在包含主方法的类里面定义一个方法,将加减乘除的逻辑放到该方法里。main方法调用此方法;
    3. 重新定义一个计算器类,将加减乘除的方法挪到该类中。main方法调用该类的方法。

    1和2中方法的调用者和被调用者高度重合,耦合度非常高。3减低了耦合度,调用者和被调用者分离,但是所有的计算方法拥挤在一个类中,修改程序变得危险。

    假如一个新手需要在计算器类中新增一个方法,但是他不小心改动了其他已有的方法,这样就很危险了!

    利用继承和多态的特点完善下

    定义一个抽象父类 Operation,Operation 类中定义两个成员变量 numberA 和 numberB,以及一个抽象方法 getResult()。

    加减乘除分别定义一个单独的类 OperationAdd、OperationSub、OperationMul、OperationDiv 都继承 Operation 类

    加减乘除类都需要重写抽象父类的 getResult(),我们将计算逻辑放到 getResult() 里。

    public abstract class Operation {
      public double numberA=0;
      public double numberB=0;
    
      public abstract double getResult();
    }
    
    public class OperationAdd extends Operation {
      public double getResult() {
        double result=0;
        result = numberA+numberB;
        return result;
      }
    }
    
    public class OperationSub extends Operation {
      public double getResult() {
        double result=0;
        result = numberA-numberB;
        return result;
      }
    }
    
    public class OperationMul extends Operation {
      public double getResult() {
        double result=0;
        result = numberA*numberB;
        return result;
      }
    }
    
    public class OperationDiv extends Operation {
      public double getResult() {
        double result=0;
        result = numberA/numberB;
        return result;
      }
    }

    测试方法

    public class Test {
      public static void main(String[] args) {
        double numberA=1;
        double numberB=2;
           //定义引用变量operation用以指向不同的实例(多态)。
        Operation opAdd = new OperationAdd();
        opAdd.numberA=numberA;
        opAdd.numberB=numberB;
        double resultAdd = opAdd.getResult();
        System.out.println("resultAdd=="+resultAdd);
    
        Operation opSub = new OperationSub();
        opSub.numberA=numberA;
        opSub.numberB=numberB;
        double resultSub = opSub.getResult();
        System.out.println("resultSub=="+resultSub);
    
        Operation opMul = new OperationMul();
        opMul.numberA=numberA;
        opMul.numberB=numberB;
        double resultMul = opMul.getResult();
        System.out.println("resultMul=="+resultMul);
    
        Operation opDiv = new OperationDiv();
        opDiv.numberA=numberA;
        opDiv.numberB=numberB;
        double resultDiv = opDiv.getResult();
        System.out.println("resultDiv=="+resultDiv);
      }
    }

    现在程序之间的耦合度大大降低,如果需要添加其他的运算方法,只需创建一个类,继承 Operation 类,实现 getResult() 即可。

    二、工厂方法模式

    工厂模式介绍:http://www.runoob.com/design-pattern/factory-pattern.html

    为什么要用工厂模式?

    个人理解:将创建对象这件事进一步封装。调用者原先需要知晓“加减乘除”具体的实现类,现在将创建实现类的任务交给工厂(工厂类负责创建)。调用者不需要知道具体实现类是什么,只需要根据一些特殊标记“+”、“-”、“*”、“/”来获取对象的实例即可

    运用工厂模式完善如下:

    public class TestFactory {
        public static Operation creatOperation(String operate) {
            Operation op = null;
            switch (operate) {
            case "+":
                op = new OperationAdd();
                break;
            case "-":
                op = new OperationSub();
                break;
            case "*":
                op = new OperationMul();
                break;
            case "/":
                op = new OperationDiv();
                break;
            default:
                break;
            }
            return op;
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Operation op = null;
            op = TestFactory.creatOperation("+");
            op.numberA=1;
            op.numberB=2;
            double result = op.getResult();
            System.out.println("result=="+result);
        }
    }

    上面根据工厂模式的改造已经达到要求了,这里只有一个工厂类,负责创建“加减乘除”类。现在试想一下,如果工厂类不止一个,对“加减乘除”类都增加一个对应的工厂类,会是什么情况?

    先构建一个工厂接口

    public interface IFactory {
        Operation createOperation();
    }

    然后为“加减乘除”各建一个具体工厂去实现 IFactory 接口

    public class AddFactory implements IFactory {
        @Override
        public Operation createOperation() {
            return new OperationAdd();
        }
    }
    
    public class SubFactory implements IFactory {
        @Override
        public Operation createOperation() {
            return new OperationSub();
        }
    }
    
    public class MulFactory implements IFactory {
        @Override
        public Operation createOperation() {
            return new OperationMul();
        }
    }
    
    public class DivFactory implements IFactory {
        @Override
        public Operation createOperation() {
            // TODO Auto-generated method stub
            return new OperationDiv();
        }
    }

    测试方法

    public class Test {    
        public static void main(String[] args) {
            IFactory openFactory = new AddFactory();
            Operation op = openFactory.createOperation();
            op.numberA=1;
            op.numberB=2;
            double resultAdd = op.getResult();
            System.out.println("resultAdd=="+resultAdd);
        }
    }

    我们发现,这样的写法不但没有简化代码,而且增加了很多类。原本我们增加一个计算的需求只需要增加一个功能类,再修改工厂类就可以了,现在不但增加功能类,还需要增加对应的工厂类,而且原本调用哪个计算类是由工厂类判断,主程序只需传一个“标记”即可,现在是由主程序自己判断该调用哪个工厂类来获取所需的功能类。

    增加了代码却没有减少操作,为什么要这样改变?

    我们把第一种模式称为简单工厂模式,第二种模式称为工厂方法模式,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据 main 方法的“标记”动态实例化相关的类,对于 main 方法来说,去除了与具体计算类的依赖。但是这样违反了“开放-封闭原则”,增加计算方法都需要取修改工厂类,不但对扩展开放了,也对修改开放了。于是工厂方法模式来了。

    工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。

    工厂方法模式实现时,main 方法需要去决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,工厂方法把简单工厂的内部逻辑判断移到了 main 方法中进行。想要加功能,本来是改工厂类的,而现在是修改 main 方法。

    工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。但缺点是由于每加一个计算方法,就需要加一个计算工厂类,增加了额外的开发量。

    至于 main 方法里的判断问题,可以利用“反射”解决。

  • 相关阅读:
    Kinect 开发 —— 硬件设备解剖
    Kinect 开发 —— 引言
    (转)OpenCV 基本知识框架
    OpenCV —— 摄像机模型与标定
    OpenCV —— 跟踪与运动
    OpenCV —— 图像局部与分割(二)
    OpenCV —— 图像局部与部分分割(一)
    OpenCV —— 轮廓
    OpenCV —— 直方图与匹配
    OpenCV —— 图像变换
  • 原文地址:https://www.cnblogs.com/jwen1994/p/9970048.html
Copyright © 2011-2022 走看看