再简单工厂模式中,如果要添加新的产品,为了配合使用就必须修改工厂类,无疑这就破坏了”开放-闭合“原则。但是这也是简单工厂的优点,简单工厂类包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,取出来客户端对具体产品的依赖。为了解耦合和符合”开放-闭合“原则,工厂模式来了。
定义:定义一个用于创建对象的工厂接口,让子类决定实例化哪一个类。核心工厂类成为一个抽象工厂角色,负责工厂子类必须实现的接口,达到添加新的产品时不必修改核心工厂类,而是添加工厂子类。
UML类图如下
继续沿用上篇简单工厂中的例子,实现如下。
首先是产品类,这里是运算符类,两个操作数参数和一个运算方法,此处用的是抽象类:
public abstract class Operation { private double numberA; private double numberB; public double getNumberA() { return numberA; } public void setNumberA(double numberA) { this.numberA = numberA; } public double getNumberB() { return numberB; } public void setNumberB(double numberB) { this.numberB = numberB; } public abstract double getResult(); }
具体产品衍生类,便是各个运算符的运算(加减乘除等),需要继承或实现产品类:
public class OperationAdd extends Operation { @Override public double getResult() { return getNumberA() + getNumberB(); } } public class OperationSub extends Operation { @Override public double getResult() { return getNumberA() - getNumberB(); } } public class OperationMul extends Operation { @Override public double getResult() { return getNumberA() * getNumberB(); } } public class OperationDiv extends Operation { @Override public double getResult() { return getNumberA() / getNumberB(); } }
其次是核心工厂类,是一个接口
public interface IFactory { public Operation createOperation(); }
具体实现工厂的子类,便是各个运算符的运算(加减乘除等),需要实现核心工厂类:
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() { return new OperationDiv(); } }
最后是客户端,调用
public class POC { public static void main(String[] args) { coal(); } public static void coal() { try { double numberA, numberB; String opr; @SuppressWarnings("resource") Scanner sc = new Scanner(System.in); System.out.print("输入第一个数字:"); String numberAStr = sc.next(); numberA = Double.parseDouble(numberAStr); System.out.print("输入操作符:"); opr = sc.next(); System.out.print("输入第二个数字:"); String numberBStr = sc.next(); numberB = Double.parseDouble(numberBStr); IFactory factory = null; switch (opr) { case "+": factory = new AddFactory(); break; case "-": factory = new SubFactory(); break; case "*": factory = new MulFactory(); break; case "/": factory = new DivFactory(); break; default: factory = new AddFactory(); break; } Operation operation = factory.createOperation(); operation.setNumberA(numberA); operation.setNumberB(numberB); System.out.println(numberAStr + opr + numberBStr + "=" + operation.getResult()); } catch (Exception e) { System.out.println("输入有误,请重新开始。。。"); coal(); } } }
可以看出添加产品时没有修改的变化,只有扩展的变化。但是,实例化工厂时选择判断的问题还是存在的,只是从工厂类移动到了客户端。但是,工厂方法模式既克服了简单工厂违背的设计原则,也保持了封装对象创建过程的优点,更换对象时不需要大范围的更改,降低了客户端与产品对象的耦合度。
工厂方法模式是简单工厂的进一步抽象和推广,利用了多态性保证了简单工厂的优点克服了缺点。但是没有避免修改客户端代码的诟病还是存在,所以可以利用反射解决分支问题,关于这点,以后再谈。