再简单工厂模式中,如果要添加新的产品,为了配合使用就必须修改工厂类,无疑这就破坏了”开放-闭合“原则。但是这也是简单工厂的优点,简单工厂类包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,取出来客户端对具体产品的依赖。为了解耦合和符合”开放-闭合“原则,工厂模式来了。
定义:定义一个用于创建对象的工厂接口,让子类决定实例化哪一个类。核心工厂类成为一个抽象工厂角色,负责工厂子类必须实现的接口,达到添加新的产品时不必修改核心工厂类,而是添加工厂子类。
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();
}
}
}
可以看出添加产品时没有修改的变化,只有扩展的变化。但是,实例化工厂时选择判断的问题还是存在的,只是从工厂类移动到了客户端。但是,工厂方法模式既克服了简单工厂违背的设计原则,也保持了封装对象创建过程的优点,更换对象时不需要大范围的更改,降低了客户端与产品对象的耦合度。
工厂方法模式是简单工厂的进一步抽象和推广,利用了多态性保证了简单工厂的优点克服了缺点。但是没有避免修改客户端代码的诟病还是存在,所以可以利用反射解决分支问题,关于这点,以后再谈。