工厂模式概念
实例化对象,用工厂方法来代替new操作
工厂模式包括简单工厂模式、工厂方法模式、抽象工厂模式
抽象工厂模式是工厂方法模式的拓展
工厂模式的意图
实现了创建者和调用者的分离
定义一个接口来创建对象,让子类决定哪些对象需要被实例化
工厂方法模式把实例化的工作推迟到子类去实现
什么情况需要工厂模式
- 有一组类似的对象需要被创建
- 在编码时不能预见需要创建哪种类的实例
- 系统需要考虑拓展性
工厂模式详细分类
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
遵循的面向对象设计原则(了解)
- 开闭原则:对拓展开发,对修改关闭。在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码
- 依赖倒转原则:针对接口而不是针对实现编程。该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代
- 迪米特法则:米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。只与朋友通信,避免和陌生人通信
没有工厂的情况
接口:车
1 | public interface Car { |
实现类:宝马
1 | public class BmwCar implements Car { |
实现类:比亚迪
1 | public class BydCar implements Car { |
测试类:
1 | public class Test { |
分析:
在没有工厂模式的情况下,调用者需要知道实现的接口,还需要知道其每一个实现类的实现方式
若上文演示的实现类都需要设置复杂的参数,那么对于调用者来说是违反迪米特法则的
(一)简单工厂模式
我们在其他类都保持原样的情况下,添加这样一个工厂如下:
简单工厂:
1 | public class SimpleFactory { |
测试类:
1 | public class Test { |
分析:
在简单工厂方法当中,我们调用者已经不需要知道实现类被创造的细节,但是依然存在一个问题:
简单工厂是依赖if、else判断来决定创造哪一个实现类的对象的,那么如果我们需要增加新的实现类、删除原有实现类,都要频繁修改工厂类
这违反了上述的开闭原则,不过在业务不需要频繁变更的项目当中,已经可以使用了
(二)工厂方法模式
- 为了避免简单工厂模式不遵守开闭原则的缺点
- 工厂方法模式和简单工厂模式的不同点在于:简单工厂模式往往只有一个工厂类,而工厂方法模式有一组实现了相同接口的工厂类
在不改变没有使用工厂模式情况下的代码的前提下,我们创建这样的工厂方法:
首先,创建一个工厂的接口,用于规范一系列工厂的行为
工厂的接口:
1 | public interface Factory { |
其次,我们创建各个种类对象的分工厂,这些分工厂统一实现工厂接口
分工厂:
1 | public class FactoryBmw implements Factory { |
1 | public class FactoryByd implements Factory { |
这些分工厂一样可以隐藏实现这些对象的细节,遵循迪米特法则
测试类:
1 | public class Test { |
分析:
使用工厂方法模式,如果需要添加新的实现类,只需要创建新的分工厂实现工厂接口即可;如果需要删除实现类,只需要删除对应的分工厂即可
这样的设计完美实现了开闭原则的要求
(三)抽象工厂模式
- 用于生产不同产品族的全部产品(对于增加单个产品无能为力,支持增加一个产品族)
- 抽象工厂模式和工厂方法模式处理的是不同的场景。在存在多个业务分类时,可以使用此模式创造一整个族的产品
由于抽象工厂模式的复杂性,我们这里使用全新的案例分析:
产品族:
汽车产品族1:低端轮胎、低端座椅、低端发动机
汽车产品族2:高端轮胎、高端座椅、高端发动机
抽象工厂模式就是用于直接生成一个产品族内全部对象的工厂模式
发动机模块:
1 | /** |
座椅模块:
1 | /** |
轮胎模块:
1 | /** |
下面就要创建整合我们的产品族中每一个模块的整合对象:Car了,汽车工厂接口负责定义每一个汽车分工厂的规范
1 | /** |
测试类:
1 | public class Test { |
分析:
按照上文演示的测试类,即可创造出一个高端汽车产品族所需的所有模块。如果我们需要一辆中档的汽车(混合高端引擎和低端座椅),那么我们仅需要创建一个中档汽车工厂,并实现汽车工厂接口,在其对应方法中创造出对应产品,即可创造一条新的产品族
在实际应用当中,如果我们的业务不需要创建一个庞大的产品族,抽象工厂模式很少用到
总结
工厂模式的应用场景:
- JDK中Calendar的getInstance()方法
- JDBC中Connection对象的获取
- Hibernate当中,使用SQLSessionFactory创建SQLSession
- Spring中,IOC容器创建管理Bean对象
- XML文件解析时,DocumentBuilderFactory创建解析器对象
- 反射中Class对象的newInstance()方法