zoukankan      html  css  js  c++  java
  • 工厂方法(FactoryMethod)模式

      之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个case分支。也就是说我们不但对扩展开发了,也对修改开放了,违背了开闭原则。当然如果工厂类采用反射的话不存在这个问题。(实际工作中工厂类使用反射也是最常见的运用方式)

      工厂方法模式(多态性工厂或虚拟构造子模式):定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类中。

      工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算进行,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你要想加功能,本来是要改工厂类的,现在变成改客户端。解决简单工厂的工厂类中复杂的创建具体对象的业务逻辑判断,如果工厂类采用反射创建对象则不需要解决这种问题。

      还是以运算类为例,把工厂抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后所有的要生产具体类的工厂去实现这个接口。这样,一个简单工厂模式的工厂类就变成了一个工厂抽象接口和多个具体生成对象的工厂。

      类图如下:

    上面设计到的角色解释:

    抽象工厂(OperationFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。实际工作中,这个角色也常常使用抽象类实现。(或者使用接口+抽象类更好的封装)

    具体工厂(OperationAddFactory、OperationSubFactory。。。)角色:担任这个角色的是实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建运算类。

    抽象运算(Operation)角色:工厂方法模式所创建的对象的超类,也就是所有运算类的共同父类或共同拥有的接口。实际工作中,这个角色也常常使用抽象类实现。(或者使用接口+抽象类更好的封装,如上就运用抽象类+接口+继承)

    具体运算(OperationAdd、OperationSub。。。)角色:这个角色实现了实现了抽象运算所声明的接口,工厂方法模式所创建的每一个对象都是某个具体运算角色的实例。

    代码如下:

    运算类相关代码

    package cn.qlq;
    
    public interface Operation {
    
        String operateType();
    
        Number operate(Number... nums);
    }
    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);
    }
    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 OperationSub extends AbstractOperation {
    
        @Override
        public String operateType() {
            return "OperationSub";
        }
    
        @Override
        public Number doOperate(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 extends AbstractOperation {
    
        @Override
        public String operateType() {
            return "OperationMul";
        }
    
        @Override
        public Number doOperate(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 extends AbstractOperation {
    
        @Override
        public String operateType() {
            return "OperationDiv";
        }
    
        @Override
        public Number doOperate(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 interface OperationFactory {
    
        /**
         * 
         * @param type
         * @return
         */
        Operation generateOperation(String type);
    }
    package cn.qlq;
    
    public class OperationAddFactory implements OperationFactory {
    
        @Override
        public Operation generateOperation(String type) {
            return new OperationAdd();
        }
    
    }
    package cn.qlq;
    
    public class OperationSubFactory implements OperationFactory {
    
        @Override
        public Operation generateOperation(String type) {
            return new OperationSub();
        }
    
    }
    package cn.qlq;
    
    public class OperationMulFactory implements OperationFactory {
    
        @Override
        public Operation generateOperation(String type) {
            return new OperationMul();
        }
    
    }
    package cn.qlq;
    
    public class OperationDivFactory implements OperationFactory {
    
        @Override
        public Operation generateOperation(String type) {
            return new OperationDiv();
        }
    
    }

    客户端测试代码:

    package cn.qlq;
    
    public class MainClass {
    
        public static void main(String[] args) {
            // 客户端判断使用哪一种工厂
            String operationType = "OperationAdd";
            OperationFactory operationFactory = new OperationAddFactory();
    
            // 生成具体的运算类
            Operation operation = operationFactory.generateOperation(operationType);
            System.out.println(operation.operateType());
            Number operate = operation.operate(1, 2);
            System.out.println(operate);
        }
    
    }

      工厂模式可以理解为将原来简单工厂的判断创建哪一个具体产品的逻辑交给客户端,客户端需要判断采用哪一个工厂。

          上面工厂类的generateOperation方法传入String类型的参数也是有用的,比如:对于减法运算,有时候第一个减后面所有的数,有时候最后一个减前面所有的数。这时候设计到的两种运算规则就可以通过参数类型创建不同的运算类,如下:

    (1)增加最后一个数减前面数的运算类:

    package cn.qlq;
    
    public class OperationSubReverse extends AbstractOperation {
    
        @Override
        public String operateType() {
            return "OperationSubReverse";
        }
    
        @Override
        public Number doOperate(Number... nums) {
            int length_1 = nums.length;
            Number result = nums[length_1 - 1];
            for (int i = 0; i < length_1; i++) {
                if (i == length_1 - 1) {
                    continue;
                }
                result = result.doubleValue() - nums[i].doubleValue();
            }
    
            return result;
        }
    
    }

    (2)重写减法工厂类

    package cn.qlq;
    
    public class OperationSubFactory implements OperationFactory {
    
        @Override
        public Operation generateOperation(String type) {
            if ("OperationSubReverse".equals(type)) {
                return new OperationSubReverse();
            } else if ("OperationSub".equals(type)) {
                return new OperationSub();
            }
    
            return null;
        }
    
    }

    工厂方法模式和简单工厂方法模式:

      工厂方法模式和简单工厂模式在结构上的不同很明显。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
      工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么不妨把抽象工厂类合并到具体工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改为静态方法,这时候就得到了简单工厂模式。

  • 相关阅读:
    Linux 格式化扩展分区(Extended)
    linux编译警告 will be initialized after
    Flutter移动电商实战 --(36)FlutterToast插件使用
    Flutter移动电商实战 --(35)列表页_上拉加载更多制作
    Flutter移动电商实战 --(34)列表页_小BUG的修复
    Flutter移动电商实战 --(33)列表页_子类和商品列表交互效果
    Flutter移动电商实战 --(32)列表页_小类高亮交互效果制作
    Flutter移动电商实战 --(31)列表页_列表切换交互制作
    Flutter移动电商实战 --(30)列表页_商品列表UI界面布局
    Flutter移动电商实战 --(29)列表页_商品列表数据模型建立
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10999159.html
Copyright © 2011-2022 走看看