简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
简单工厂就是将多个if,else...代码块拆开,增加代码的可阅读性、便于后期的维护。一个接口,几个实现接口的类,再通过传参的形式在工厂类中根据类型去创建相应的具体类。
其结构如下图:
以最简单的加减乘除运算为例,建立一个通用的运算接口,其有两个抽象方法:一个是描述运算类型,另一个是具体的运算。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"... 代码块。
优点:
该模式的核心是工厂类。工厂类中含有必要的逻辑判断,调用者不需要关注创建对象的部分,去除了与具体产品的依赖。简单工厂模式通过这种做法实现了对责任的分割,当系统引入新的运算的时候无需修改调用者。
缺点:
(重要)
对上面的简单工厂模式做一个简单的改造:新增一抽象类实现上面的接口,具体的运算类继承抽象类,并重写抽象类的抽象方法。
这么做的好处是可以做到更好的封装,做一些前处理,验证参数等参数,当然也可以在抽象类中做一些后处理等操作。而且采用反射与约定的命名规则创建对象,增加一个新的运算规则的时候不需要改动工厂类(利用反射避免工厂类中分支判断的问题)。
改造如下:
(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; } }