介绍
工厂模式也称 简单工厂模式,是创建型设计模式的一种。工厂模式提供了按需创建对象的最佳方式,并且不会对外暴露创建细节,通过一个统一的接口创建所需对象。
使用工厂模式,你不需要知道对象是怎么创建出来的,不需要你去 new,调用者想要创建一个对象,知道对象的名称即可。
意图
定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
场景
假设现在有一个造车厂,可以生产奥迪、奔驰、福特三种类型的汽车。那么此时用户要买车,只需要告诉造车厂我需要什么车,不需要知道车是如何造出来的。
不使用工厂模式来实现需求
创建三种汽车类
public class AudiCar {public CarInfo getAudiInfo() {return new CarInfo("奥迪", 800000.00, "银白色");}}public class BenzCar {public CarInfo getBenzInfo() {return new CarInfo("奔驰", 700000.00, "黑色");}}public class FuteCar {public CarInfo getFuteCarInfo() {return new CarInfo("福特", 600000.00, "黄色");}}
测试:
@Slf4jpublic class FactoryTest {public static void main(String[] args) throws InstantiationException, IllegalAccessException {getCar(1);}public static void getCar(int carType) {if (1 == carType) {AudiCar audiCar = new AudiCar();CarInfo info = audiCar.getInfo();log.info("{}", JSON.toJSONString(info));} else if (2 == carType) {BenzCar benzCar = new BenzCar();CarInfo info = benzCar.getInfo();log.info("{}", JSON.toJSONString(info));} else if (3 == carType) {FuteCar futeCar = new FuteCar();CarInfo info = futeCar.getInfo();log.info("{}", JSON.toJSONString(info));}else {throw new RuntimeException("没有该车型!");}}}
可以看到,上述代码使用了大量的 if…else 语句,也能够实现业务需求。但是如果后序又来了其他的汽车类型,又要往里面加 if…else,这样的代码使用的时间越久,重构起来的成本也就越高,重构前要清理所有的使用方,成本很高。所以可以使用工厂模式来尽量避免上述问题。
工厂模式重构代码
第一步
创建一个接口,此接口定义了获取车辆信息的规范。
public interface Car {/*** 获取车信息** @return 车信息*/CarInfo getInfo();}
车辆信息封装对象:
@Data@NoArgsConstructor@AllArgsConstructorpublic class CarInfo {private String name;private Double price;private String color;}
第二步
创建接口的具体实现类,这里是奥迪、奔驰、福特三个子类。
public class AudiCar implements Car {@Overridepublic CarInfo getInfo() {return new CarInfo("奥迪", 800000.00, "银白色");}}
public class BenzCar implements Car {@Overridepublic CarInfo getInfo() {return new CarInfo("奔驰", 700000.00, "黑色");}}
public class FuteCar implements Car {@Overridepublic CarInfo getInfo() {return new CarInfo("福特", 600000.00, "黄色");}}
从上述代码中,可以看到,每种车型的实现都包装到自己的类中,当要新增、修改、删除逻辑时,不会影响到其它车型的功能代码。
第三步
创建工厂。
public class CarFactory {public Car getInstance(CarType carType) {if (1 == carType.getType()) {return new AudiCar();}if (2 == carType.getType()) {return new BenzCar();}if (3 == carType.getType()) {return new FuteCar();}throw new RuntimeException("不存在该车型");}public Car getInstance(Class<? extends Car> clazz) throws IllegalAccessException, InstantiationException {if (clazz == null) { return null;}return clazz.newInstance();}}
其中 CarType 是一个枚举类。
public enum CarType {AUDI(1),BENZ(2),FUTE(3);private int type;private CarType(int type) {this.type = type;}public int getType() {return type;}}
此工厂便是用来生产汽车对象的。通过用户传入的类型,来指定生成的车辆类型。
测试
@Slf4jpublic class FactoryTest {public static void main(String[] args) throws InstantiationException, IllegalAccessException {CarFactory carFactory = new CarFactory();Car instance = carFactory.getInstance(CarType.AUDI);log.info("{}", JSON.toJSON(instance.getInfo()));Car instance1 = carFactory.getInstance(BenzCar.class);log.info("{}", JSON.toJSON(instance1.getInfo()));}}
小结
工厂模式避免创建者和具体的产品实现逻辑耦合在一起;满足单一责任,每一个业务逻辑都在自己本类中完成。同时满足开闭原则,对扩展是开放的,对修改是关闭的。
但如果产品种类过多,那么子类就会急速扩展,需要配合其他模式进行优化。
