简单工厂模式(Simple Factory Pattern)就是最简单的工厂模式实现。工厂模式的使用场景是十分明显的。举例来说,假设有一个接口Interface存在于代码包package中供使用者使用,这个接口有很多实现类,ClassA,ClassB,ClassC...,它们都包含在代码包中。现在我们要使用Interface的特性,如果不使用工厂模式,但是又想利用面向对象多态的特性,使程序具有较好的可扩展性,我们恐怕要这样写:
Interface i = new ClassA();
当我们想要换一种Interface的实现时,恐怕就要把new
的对象换一下了。但是这样做不好,使用者需要知道ClassA,ClassB等,使用者写出来的代码和代码包package中的实现细节耦合过深了。用户使用的是接口的特性,却不得不关注ClassX这些实现类,使用者本不应该关心这些的。因此工厂模式诞生了,使用者调用工厂,工厂根据使用者描述的需求,自动返回一个类的实例供使用者使用。使用者只需知道,用的是Interface,其实例通过工厂获取。
Interface i = Factory.getInstance(description);
下面例子中,我们实现一个控制台程序,用户输入例如1 + 2
,输出结果3
,支持加减乘除操作。
Calculator.java
public interface Calculator {
public abstract double calculate(double x, double y);
}
AddCalculator.java
public class AddCalculator implements Calculator {
@Override
public double calculate(double x, double y) {
return x + y;
}
}
CalculatorFactory.java
public class CalculatorFactory {
public static Calculator getCalculator(String operation) {
if ("+".equals(operation)) {
return new AddCalculator();
} else if ("-".equals(operation)) {
return new SubCalculator();
} else if ("*".equals(operation)) {
return new MultCaculator();
} else if ("/".equals(operation)) {
return new DivCalculator();
} else {
throw new RuntimeException("未支持运算");
}
}
}
Main.java
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double x = scanner.nextDouble();
String operation = scanner.next();
double y = scanner.nextDouble();
Calculator calculator = CalculatorFactory.getCalculator(operation);
System.out.println(calculator.calculate(x, y));
scanner.close();
}
}
上述代码中,我们首先定义了一个运算符接口,这个接口表示一种“行为”,即运算符类能够执行运算操作。四个运算符实现类实现运算符接口,这里因为篇幅,代码中只列出了AddCalculator
,实际上还定义了SubCalculator
,MultCaculator
,DivCalculator
。工厂类CalculatorFactory
包含静态方法getCalculator()
,该方法中我们根据对需要的运算符的描述信息,实例化正确的运算符返回给用户。
你可能发现了,这么写不是有病吗?我用Python甚至一行即可解决该需求print(eval(input()))
,上面代码这一写就是7个文件90行代码。
但是我们要知道,如果项目架构变得越来越大,使用设计模式的优越性就会凸现出来。上面代码中,我们首先利用接口实现了运算符类的抽象,其次利用简单工厂模式实现了使用者和接口实现类之间的解耦。当需求发生改变时,例如添加一个新的自定义运算符mod
,此时我们直接实现Calculator
接口创建ModCaculator
并并修改工厂类实现即可,使用者使用工厂类进行运算还是一样的方便,并且无需关注ModCaculator
。