工厂方法模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类,在添加新的产品时,整个工厂和产品体系都无变化,只是扩展发生变化,符合开放-封闭原则。工厂方法模式实现时,客户端需要决定实例化哪一个工厂,选择判断的问题还是存在的,只是把简单工厂的内部逻辑判断移到了客户端。
结构图
UML类图
示例代码
Operation.java
abstract class Operation {
private double NumberA;
private double NumberB;
public void setNumberA(double a) {
NumberA = a;
}
public double getNumberA() {
return NumberA;
}
public void setNumberB(double b) {
NumberB = b;
}
public double getNumberB() {
return NumberB;
}
public abstract double getResult() throws Exception;
}
class OperationAdd extends Operation {
@Override
public double getResult() {
return getNumberA() + getNumberB();
}
}
class OperationSub extends Operation {
@Override
public double getResult() {
return getNumberA() - getNumberB();
}
}
class OperationMul extends Operation {
@Override
public double getResult() {
return getNumberA() * getNumberB();
}
}
class OperationDiv extends Operation {
@Override
public double getResult() throws Exception {
if(getNumberB() == 0)
throw new Exception("除数不能为0");
return getNumberA() / getNumberB();
}
}
OperationFactory.java
public interface OperationFactory {
Operation createOperate();
}
class AddFactory implements OperationFactory {
public Operation createOperate() {
return new OperationAdd();
}
}
class SubFactory implements OperationFactory {
public Operation createOperate() {
return new OperationSub();
}
}
class MulFactory implements OperationFactory {
public Operation createOperate() {
return new OperationMul();
}
}
class DivFactory implements OperationFactory {
public Operation createOperate() {
return new OperationDiv();
}
}
Main.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Scanner s = new Scanner(System.in);
OperationFactory factory;
System.out.println("请输入数字A:");
double numberA = s.nextDouble();
System.out.println("请输入运算符(+,-,*,/):");
switch (s.next()) {
case "+": factory = new AddFactory();break;
case "-": factory = new SubFactory();break;
case "*": factory = new MulFactory();break;
case "/": factory = new DivFactory();break;
default:
throw new IllegalStateException("Unexpected value");
}
System.out.println("请输入数字B:");
double numberB = s.nextDouble();
Operation opr = factory.createOperate();
opr.setNumberA(numberA);
opr.setNumberB(numberB);
System.out.println("结果:" + opr.getResult());
s.close();
}
}
优缺点
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程
- 灵活性增强 对于新产品的创建,只需多写一个相应的工厂类
- 典型的解耦框架 高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决
适用场景
- 客户只知道创建产品的工厂名,而不知道具体的产品名
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口
- 客户不关心创建产品的细节,只关心产品的品牌