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 方法里的判断问题,可以利用“反射”解决。

  • 相关阅读:
    Ubuntu 网络代理配置
    WSL2 环境配置
    两台笔记本电脑实现同一wifi下虚拟主机网络实现互通
    Linux /dev/loop0文件详解
    Excel两张表查重,返回True
    计算机网络基础/进制转换/企业级子网IP划分
    leetcode 2030. 含特定字母的最小子序列
    nginx https
    kubernetes(二十四)ingress https
    求两个向量的旋转矩阵 E
  • 原文地址:https://www.cnblogs.com/jwen1994/p/9970048.html
Copyright © 2011-2022 走看看