zoukankan      html  css  js  c++  java
  • 简单工厂(SimpleFactory)模式

      简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。

      简单工厂就是将多个if,else...代码块拆开,增加代码的可阅读性、便于后期的维护。一个接口,几个实现接口的类,再通过传参的形式在工厂类中根据类型去创建相应的具体类。

    其结构如下图:

    1.  最常见的简单工厂

      以最简单的加减乘除运算为例,建立一个通用的运算接口,其有两个抽象方法:一个是描述运算类型,另一个是具体的运算。UML类图如下:

    对应的代码如下:

    package cn.qlq;
    
    public interface Operation {
    
        String operateType();
    
        Number operate(Number... nums);
    }
    package cn.qlq;
    
    public class OperationAdd implements Operation {
    
        @Override
        public String operateType() {
            return "OperationAdd";
        }
    
        @Override
        public Number operate(Number... nums) {
            Number result = 0;
            for (Number number : nums) {
                result = result.doubleValue() + number.doubleValue();
            }
    
            return result;
        }
    
    }
    package cn.qlq;
    
    public class OperationSub implements Operation {
    
        @Override
        public String operateType() {
            return "OperationSub";
        }
    
        @Override
        public Number operate(Number... nums) {
            Number result = nums[0];
            for (int i = 0, length_1 = nums.length; i < length_1; i++) {
                if (i == 0) {
                    continue;
                }
                result = result.doubleValue() - nums[i].doubleValue();
            }
    
            return result;
        }
    
    }
    package cn.qlq;
    
    public class OperationMul implements Operation {
    
        @Override
        public String operateType() {
            return "OperationMul";
        }
    
        @Override
        public Number operate(Number... nums) {
            Number result = nums[0];
            for (int i = 0, length_1 = nums.length; i < length_1; i++) {
                if (i == 0) {
                    continue;
                }
                result = result.doubleValue() * nums[i].doubleValue();
            }
    
            return result;
        }
    
    }
    package cn.qlq;
    
    public class OperationDiv implements Operation {
    
        @Override
        public String operateType() {
            return "OperationDiv";
        }
    
        @Override
        public Number operate(Number... nums) {
            Number result = nums[0];
            for (int i = 0, length_1 = nums.length; i < length_1; i++) {
                if (i == 0) {
                    continue;
                }
                result = result.doubleValue() / nums[i].doubleValue();
            }
    
            return result;
        }
    
    }

    工厂类:根据运算类型创建不同的对象,遇到不合法的运算抛出一个运行时异常。

    package cn.qlq;
    
    public class OperationFactory {
    
        public static Operation generateOperation(String type) {
            Operation operation = null;
            switch (type) {
            case "OperationAdd":
                operation = new OperationAdd();
                break;
            case "OperationSub":
                operation = new OperationSub();
                break;
            case "OperationMul":
                operation = new OperationMul();
                break;
            case "OperationDiv":
                operation = new OperationDiv();
                break;
            default:
                break;
            }
    
            if (operation == null) {
                throw new RuntimeException("不合法的运算类型");
            }
    
            return operation;
        }
    }

    测试代码:

    package cn.qlq;
    
    public class MainClass {
    
        public static void main(String[] args) {
            String operationType = "OperationDiv";
            Operation operation = OperationFactory.generateOperation(operationType);
            if (operation == null) {
                System.out.println("未知类型");
                return;
            }
    
            System.out.println(operation.operateType());
            Number operate = operation.operate(1, 2);
            System.out.println(operate);
        }
    
    }

    现在假设我们不用简单工厂模式,伪代码如下:

    package cn.qlq;
    
    public class MainClass {
    
        public static void main(String[] args) {
            String operationType = "OperationDiv";
            if ("OperationDiv".equals(operationType)) {
                // 处理加法
                
            } else if ("OperationSub".equals(operationType)) {
                // 处理减法
                
            } else if ("OperationMul".equals(operationType)) {
                // 处理乘法
                
            } else if ("OperationDiv".equals(operationType)) {
                // 处理除法
                
            } else {
                throw new RuntimeException("error type");
            }
        }
    
    }

      上面代码确实看着比较繁琐,而且不易扩展。

      将来如果我们增加一种求平方根的运算,需要在增加一个else if ... 代码块,并且在该代码块中增加处理平方根的代码块。而如果使用了上面的简单工厂模式的话需要增加一个具体的实现类,并且在工厂类中增加1个 case "OperationSquare"... 代码块。

    优点:

     该模式的核心是工厂类。工厂类中含有必要的逻辑判断,调用者不需要关注创建对象的部分,去除了与具体产品的依赖。简单工厂模式通过这种做法实现了对责任的分割,当系统引入新的运算的时候无需修改调用者。

    缺点:

        如果需要在方法里写很多与对象创建有关的业务代码,而且需要的创建的对象还不少的话,我们要在这个简单工厂类里编写很多个方法,每个方法里都得写很多相应的业务代码,而每次增加子类或者删除子类对象的创建都需要打开这简单工厂类来进行修改。这会导致这个简单工厂类很庞大臃肿、耦合性高,而且增加、删除某个子类对象的创建都需要打开简单工厂类来进行修改代码也违反了开-闭原则。

     2.  利用反射改造工厂-去掉工厂类中的分支判断(重要)

      对上面的简单工厂模式做一个简单的改造:新增一抽象类实现上面的接口,具体的运算类继承抽象类,并重写抽象类的抽象方法。

      这么做的好处是可以做到更好的封装,做一些前处理,验证参数等参数,当然也可以在抽象类中做一些后处理等操作。而且采用反射与约定的命名规则创建对象,增加一个新的运算规则的时候不需要改动工厂类(利用反射避免工厂类中分支判断的问题)。

    改造如下:

    (1)接口仍然采用上面的接口

    (2)封装一个抽象类实现上面接口并重写其operate方法,在该方法中先验证参数,验证通过之后进行doOperate操作(一个抽象方法)

    (3)具体的实现类继承上面抽象类,并且重写doOperate方法。

    (4)工程类中采用反射创建具体的对象。

    类图如下:

    抽象类代码:

    package cn.qlq;
    
    public abstract class AbstractOperation implements Operation {
    
        @Override
        public Number operate(Number... nums) {
            if (nums == null || nums.length == 0) {
                System.out.println("非法参数");
                return 0;
            }
    
            System.out.println("参数验证通过");
            return doOperate(nums);
        }
    
        public abstract Number doOperate(Number[] nums);
    }

    以加法操作为例继承上面抽象类,重写doOperate方法即可。其他减乘除类似。

    package cn.qlq;
    
    public class OperationAdd extends AbstractOperation {
    
        @Override
        public String operateType() {
            return "OperationAdd";
        }
    
        @Override
        public Number doOperate(Number... nums) {
            Number result = 0;
            for (Number number : nums) {
                result = result.doubleValue() + number.doubleValue();
            }
    
            return result;
        }
    
    }

    工厂类:(根据类型反射创建具体的类)

      这里需要遵循一个约定:运算的类型与对应运算实现类的类名完全一致才可以进行反射创建对象。当然可以根据其他规则进行转换。

    package cn.qlq;
    
    public class OperationFactory {
    
        public static Operation generateOperation(String type) {
            String packageName = "cn.qlq.";
            String className = packageName + type;
    
            // 反射创建对应的对象
            Operation operation = null;
            try {
                Class clazz = Class.forName(className);
                operation = (Operation) clazz.newInstance();
            } catch (Exception e) {
                // 此处应该记录日志
                throw new RuntimeException("非法参数异常");
            }
    
            return operation;
        }
    }

    总结:

      简单工厂模式是由一个工厂类根据不同的参数类型创建出哪一种产品类的实例。

      工作中也是通过反射 + 简单工厂来使用的。一般将类型存在数据库中,客户端(浏览器)访问后台操作的时候根据数据库中的类型,通过简单工厂获取到对应的实例进行相应的操作。

  • 相关阅读:
    JAVA 的赋值运算符、比较运算符、逻辑运算符、三元运算符、引用数据类型、流程语句
    Java 的方向、安装、打印“HelloWorld”、注释、标识字、关键字、变量、
    oracle组函数、多表查询、分页、
    oracle 的单行函数
    JQ 的class类的操作 效果 遍历 内置遍历数组的函数 事件
    jquery的引入、入口函数、选择器、对内容的操作、对元素的操作、属性操作
    MySQL 查询习题详解
    oracle的基本查询
    数据库45道练习题
    数据库概念以及入门语句,增删改
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10996589.html
Copyright © 2011-2022 走看看