介绍

工厂模式也称 简单工厂模式,是创建型设计模式的一种。工厂模式提供了按需创建对象的最佳方式,并且不会对外暴露创建细节,通过一个统一的接口创建所需对象。
使用工厂模式,你不需要知道对象是怎么创建出来的,不需要你去 new,调用者想要创建一个对象,知道对象的名称即可。

意图

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

场景

假设现在有一个造车厂,可以生产奥迪、奔驰、福特三种类型的汽车。那么此时用户要买车,只需要告诉造车厂我需要什么车,不需要知道车是如何造出来的。

不使用工厂模式来实现需求

创建三种汽车类

  1. public class AudiCar {
  2. public CarInfo getAudiInfo() {
  3. return new CarInfo("奥迪", 800000.00, "银白色");
  4. }
  5. }
  6. public class BenzCar {
  7. public CarInfo getBenzInfo() {
  8. return new CarInfo("奔驰", 700000.00, "黑色");
  9. }
  10. }
  11. public class FuteCar {
  12. public CarInfo getFuteCarInfo() {
  13. return new CarInfo("福特", 600000.00, "黄色");
  14. }
  15. }

测试:

  1. @Slf4j
  2. public class FactoryTest {
  3. public static void main(String[] args) throws InstantiationException, IllegalAccessException {
  4. getCar(1);
  5. }
  6. public static void getCar(int carType) {
  7. if (1 == carType) {
  8. AudiCar audiCar = new AudiCar();
  9. CarInfo info = audiCar.getInfo();
  10. log.info("{}", JSON.toJSONString(info));
  11. } else if (2 == carType) {
  12. BenzCar benzCar = new BenzCar();
  13. CarInfo info = benzCar.getInfo();
  14. log.info("{}", JSON.toJSONString(info));
  15. } else if (3 == carType) {
  16. FuteCar futeCar = new FuteCar();
  17. CarInfo info = futeCar.getInfo();
  18. log.info("{}", JSON.toJSONString(info));
  19. }else {
  20. throw new RuntimeException("没有该车型!");
  21. }
  22. }
  23. }

可以看到,上述代码使用了大量的 if…else 语句,也能够实现业务需求。但是如果后序又来了其他的汽车类型,又要往里面加 if…else,这样的代码使用的时间越久,重构起来的成本也就越高,重构前要清理所有的使用方,成本很高。所以可以使用工厂模式来尽量避免上述问题。

工厂模式重构代码

第一步

创建一个接口,此接口定义了获取车辆信息的规范。

  1. public interface Car {
  2. /**
  3. * 获取车信息
  4. *
  5. * @return 车信息
  6. */
  7. CarInfo getInfo();
  8. }

车辆信息封装对象:

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class CarInfo {
  5. private String name;
  6. private Double price;
  7. private String color;
  8. }

第二步

创建接口的具体实现类,这里是奥迪、奔驰、福特三个子类。

  1. public class AudiCar implements Car {
  2. @Override
  3. public CarInfo getInfo() {
  4. return new CarInfo("奥迪", 800000.00, "银白色");
  5. }
  6. }
  1. public class BenzCar implements Car {
  2. @Override
  3. public CarInfo getInfo() {
  4. return new CarInfo("奔驰", 700000.00, "黑色");
  5. }
  6. }
  1. public class FuteCar implements Car {
  2. @Override
  3. public CarInfo getInfo() {
  4. return new CarInfo("福特", 600000.00, "黄色");
  5. }
  6. }

从上述代码中,可以看到,每种车型的实现都包装到自己的类中,当要新增、修改、删除逻辑时,不会影响到其它车型的功能代码。

第三步

创建工厂。

  1. public class CarFactory {
  2. public Car getInstance(CarType carType) {
  3. if (1 == carType.getType()) {
  4. return new AudiCar();
  5. }
  6. if (2 == carType.getType()) {
  7. return new BenzCar();
  8. }
  9. if (3 == carType.getType()) {
  10. return new FuteCar();
  11. }
  12. throw new RuntimeException("不存在该车型");
  13. }
  14. public Car getInstance(Class<? extends Car> clazz) throws IllegalAccessException, InstantiationException {
  15. if (clazz == null) { return null;}
  16. return clazz.newInstance();
  17. }
  18. }

其中 CarType 是一个枚举类。

  1. public enum CarType {
  2. AUDI(1),
  3. BENZ(2),
  4. FUTE(3);
  5. private int type;
  6. private CarType(int type) {
  7. this.type = type;
  8. }
  9. public int getType() {
  10. return type;
  11. }
  12. }

此工厂便是用来生产汽车对象的。通过用户传入的类型,来指定生成的车辆类型。

测试

  1. @Slf4j
  2. public class FactoryTest {
  3. public static void main(String[] args) throws InstantiationException, IllegalAccessException {
  4. CarFactory carFactory = new CarFactory();
  5. Car instance = carFactory.getInstance(CarType.AUDI);
  6. log.info("{}", JSON.toJSON(instance.getInfo()));
  7. Car instance1 = carFactory.getInstance(BenzCar.class);
  8. log.info("{}", JSON.toJSON(instance1.getInfo()));
  9. }
  10. }

image.png

小结

工厂模式避免创建者和具体的产品实现逻辑耦合在一起;满足单一责任,每一个业务逻辑都在自己本类中完成。同时满足开闭原则,对扩展是开放的,对修改是关闭的。
但如果产品种类过多,那么子类就会急速扩展,需要配合其他模式进行优化。