工厂方法模式–制造细节无需知
前面介绍过简单工厂模式,简单工厂模式只是最基本的创建实例相关的设计模式。在真实情况下,有更多复杂的情况需要处理。简单工厂生成实例的类,知道了太多的细节,这就导致这个类很容易出现难维护、灵活性差的问题。就像我们去饭店吃饭,只需要付钱,等成品,不需要了解这盘菜是怎么做的,如何加工的。
简单工厂
再来回顾下简单工厂模式的计算器功能的工厂类。
public static Operation createOperate(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
客户端调用时
Operation operate = OperationFactory.createOperate(strOperate);
double result = operate.getResult(numberA, numberB);
当使用工厂方法模式实现
实际就是对简单工厂中的细节部分进行再封装,让这个工厂类不需要知道很多的实现细节。是这样子吗,体验一下子。
结构图如下:
先构建一个工厂接口
public interface IFactory {
Operation createOperation();
}
然后加减乘除的工厂都去实现这个接口,并实现自己的createOeration()方法
// 加法工厂
public class AddFactory implements IFactory {
@Override
public Operation createOperation() {
return new Add();
}
}
// 减法工厂
public class SubFactory implements IFactory {
@Override
public Operation createOperation() {
return new Sub();
}
}
// 乘法工厂
public class MulFactory implements IFactory {
@Override
public Operation createOperation() {
return new Mul();
}
}
// 除法工厂
public class DivFactory implements IFactory {
@Override
public Operation createOperation() {
return new Div();
}
}
那么在对外工厂类中就可以这么实现
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
IFactory factory = null;
switch (operate) {
case "+":
factory = new AddFactory();
break;
case "-":
factory = new SubFactory();
break;
case "*":
factory = new MulFactory();
break;
case "/":
factory = new DivFactory();
break;
}
oper = factory.createOperation();
return oper;
}
}
当我需要增加新的运算功能时,需要增加运算类,运算工厂类,一下增加了好几个类,这样是不是变得更麻烦了?
简单工厂VS工厂方法
简单工厂模式的最大优点在于工厂类中包含必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
就像计算器工厂类,客户端只需要传入一个"+"或别的,就能得到想要的功能算法。
但是当我们继续增加计算器功能时,比如增加一个指数运算,增加一个对数运算,要去不断修改OperationFactory
类,就违背了开放-封闭原则
。那我们该如何降低这种风险呢?就需要使用到工厂方法模式
我们应该尽量将长的代码分派切割成小段,再将每一小段封装
起来,减少每段代码之间的耦合,这样风险就分散了,需要修改或扩展的难度就降低了。
再以计算器功能为例,项目起初,我们只知道加减乘除的功能,那我们就可以将这四个功能定义为基础运算工厂
,也就是说前期功能是确定的,作为基础功能,我们就没有必要给加减乘除类增加冗余的工厂了。
后来增加了指数、对数运算,我们定义为高级运算工厂
。
那么其实并不是如上面的代码所讲,加减乘除功能每一个功能需要一个工厂类。而是将加减乘除用一个基础工厂来创建,而后面增加新的产品功能,又不想影响原有的工厂代码,于是就扩展一个新的工厂来处理即可。
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到子类
修改结构图:
新增两个运算类(指数和对数)
// 指数
public class Pow extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return Math.pow(numberA, numberB);
}
}
// 对数运算
public class Log extends Operation {
@Override
public double getResult(double numberA, double numberB) {
return Math.log(numberB) / Math.log(numberA);
}
}
工厂接口不变
public interface IFactory {
Operation createOperation(String operType);
}
基础运算工厂类,此类已经比较成熟稳定,实现后应该封装到位,不建议轻易修改此类
public class FactoryBase implements IFactory {
@Override
public Operation createOperation(String operate) {
Operation oper = null;
switch (operate) {
case "+":
oper = new Add();
break;
case "-":
oper = new Sub();
break;
case "*":
oper = new Mul();
break;
case "/":
oper = new Div();
break;
}
return oper;
}
}
高级运算工厂类,也许还有扩展产品的可能性
public class FactoryAdvanced implements IFactory {
@Override
public Operation createOperation(String operType) {
Operation oper = null;
switch (operType) {
case "pow":
oper = new Pow();
break;
case "log":
oper = new Log();
break;
}
return oper;
}
}
那么最后一步就是对外工厂类,根据传入的参数,选择具体使用哪个工厂类。
public class OperationFactory {
public static Operation createOperate(String operate) {
Operation oper = null;
IFactory factory = null;
switch (operate) {
case "+":
case "-":
case "*":
case "/":
factory = new FactoryBase();
break;
case "pow":
case "log":
factory = new FactoryAdvanced();
}
oper = factory.createOperation(operate);
return oper;
}
}
总结
工厂方法模式是简单工厂模式的进一步抽象和推广。工厂方法模式本质就是对获取对象过程的抽象。
对于复杂的参数的构造对象,可以很好地对外层屏蔽代码的复杂性,有很好的解耦能力。