一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
上一篇文章我们讲了工厂模式的基本用法,其实上一篇文章也可以被当做一个工厂模式思想的入门。这篇文章我们将对工厂模式相关的内容做具体的介绍。
工厂模式的分类
在很多资料中,会把工厂模式相关的设计模式分为三种:
- 简单/静态工厂模式
- 工厂方法模式
- 抽象工厂模式
我们可以认为,简单工厂模式是工厂方法模式的简版,而抽象工厂模式是工厂方法模式的加强版。
使用工厂模式的好处
使用工厂模式的好处就是,使用方完全不用感知对象是怎么创建出来的,只需要知道工厂的提供的接口就可以了。这样就可以做到使用者和被使用的类的“解耦”。
如果不使用工厂模式,比如说要创建一个类A 的对象,我们需要在使用者的代码块中使用new A() 来创建一个新的对象。这样类A 就和使用者“耦合”了。
如果类A 内部需要改动什么东西,使用了工厂模式,就完全不需要使用者关心这个改动了;如果没有使用工厂模式,使用者就有可能会改动很多。
举例来说我们对于文件IO 的操作
Reader reader = new BufferedReader(new FileReader(new File("copy.txt")));
如果使用者有很多使用上述代码的情况,这个时候我们要将BufferedReader 换成其他类型的Reader 实现,那么就需要改动很多位置。但是如果使用了工厂模式,上述逻辑都在我们对应的Factory 内部实现,我们只需要变更对应的Factory 内部逻辑就好。
简单工厂方法模式我们可以参考上一篇文章,上一篇文章就是一个典型的简单工厂模式的实现。
这里我们给出“简单工厂模式”的类图,供读者参考:
而这篇文章,我们重点介绍工厂方法模式。
工厂方法模式
工厂模式组织形式还是那句话:定义一个用于创建对象的接口,让子类决定去实例化哪一个类。工厂方法使一个类的实例化延迟到子类。
我们首先给出工厂方法模式的UML 类图,参照类图和后续给出的代码来学习“工厂方法模式”。
步骤一
首先我们明确我们要创建的产品是什么,抽象出产品类型:
public interface Vehicle {
void seats();
}
步骤二
针对具体产品,有具体的产品实体类:
// 小汽车类
public class Car implements Vehicle{
@Override
public void seats() {
System.out.println("五座小汽车");
}
}
// 卡车类
public class Truck implements Vehicle{
@Override
public void seats() {
System.out.println("两座小卡车");
}
}
步骤三
有了这些目标产品之后,我们就需要一个“汽车工厂”。这个汽车工厂可以创建任何类型的汽车。定义如下:
public interface VehicleFactory {
Vehicle createVehicle();
}
步骤四
对于具体类型的产品,有不同的工厂来生产它们:
// 小汽车工厂
public class CarFactory implements VehicleFactory{
@Override
public Vehicle createVehicle() {
return new Car();
}
}
// 卡车工厂
public class TruckFactory implements VehicleFactory{
@Override
public Vehicle createVehicle() {
return new Truck();
}
}
上述声明完成之后,可以按照如下方法使用:
public static void main(String[] args) {
// 如果想要一辆小汽车
VehicleFactory carFactory = new CarFactory();
carFactory.createVehicle().seats();
// 如果想要一辆卡车
VehicleFactory truckFactory = new TruckFactory();
truckFactory.createVehicle().seats();
}
显示结果如下:
五座小汽车
两座小卡车
以上就是“工厂方法模式”的创建及使用流程。
总结
针对工厂方法模式的流程,通过对比类图和代码,结构也是比较清晰的。
从中我们也可以明显看出,客户端(使用者)不需要关心对象的创建,每个类有自己的明确职责。如果有新的对象(或者说对象类型)需要增加,我们只需要新增新的类和对应的工厂即可。对已有的结构不会产生任何影响。
但是比较明显的缺点就是如果使用场景不恰当,会新增很多额外的代码却没有什么其他收益。
所以不同的设计模式有其对应的应用场景,我们应该结果具体的场景具体分析,不要为了追求“设计模式”而生搬硬套。
这篇文章介绍的是“工厂方法模式”。在接下来的文章中我们会介绍工厂模式的另一个实现:抽象工厂模式。