要点:
- 创建与使用分离
- 静态方法
- XML配置文件
- 产品、工厂两层结构
- Java反射机制
- 产品族、产品等级结构
- 开闭原则倾斜性
一、简单工厂模式(静态工厂方法)
专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
1.模式动机:
用户无需知道苹果、香蕉、橙如何创建,只需要知道水果的名字就可以买到对应水果。
2.要点:
- 创建和使用分离
- 单一职责
- 静态方法
- 不满足“开闭原则”
- 不是GoF23中一员
3.三个角色
- 工厂:实现创建所有实例的内部逻辑。
- 抽象产品:所有对象的父类,描述所有实例共有的公共接口。
- 具体产品:创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
4.适用环境
- 工厂类负责创建的对象比较少
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心
5.优点
- 责任分割
- 客户端无需知道具体产品类名,只需知道具体产品类对应的参数
- 引入配置文件,无需修改客户端代码,更换和增加新的具体产品类
6.缺点
- 工厂类集中了所有产品创建逻辑,一旦出问题,整个系统受影响
- 增加类的个数,增加系统复杂度和理解难度
- 系统扩展困难,添加新产品需要修改工厂逻辑
- 静态工厂,工厂角色无法形成基于继承的等级结构
二、工厂方法模式
工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,,通过工厂子类确定应该实例化哪一个具体产品类。
1.模式动机
简单工厂模式不满足“开闭原则”,改进。
2.要点:
- Java反射机制
3.四个角色
- 抽象产品:定义产品的接口/父类
- 具体产品:实现抽象产品接口
- 抽象工厂:工厂方法返回产品
- 具体工厂:实现抽象工厂方法,返回具体产品类实例
具体产品由具体工厂创建,一一对应
4. 适用环境
- 一个类不知道它所需要对象的类
- 一个类通过其子类来指定创建哪个对象
- 工厂子类负责创建对象,客户端动态指定类
5.优点
- 工厂方法对用户隐藏哪种具体产品类将被实例化,用户无需知道细节
- 多态性设计,所有具体工厂类都有同一抽象父类
- 加入新产品时,只需添加具体工厂和具体产品,符合“开闭原则
6.缺点
- 类的个数成对增加,增加复杂度
- 引入抽象层,用DOM、反射,增加难度
三、抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
1.模式动机
需要一个工厂可以提供多个产品对象。
2.要点
- 多种产品(对比工厂方法模式)
- 产品等级结构:产品类别(海尔电视机、海信电视机、TCL电视机)
- 产品族:产品品牌(海尔电视机、海尔电冰箱)
3.四个角色
- 抽象工厂:定义一组方法,一个方法对应一个产品等级结构
- 具体工厂:实现抽象工厂方法,生成一组具体产品
- 抽象产品:声明接口,定义抽象方法
- 具体产品:实现抽象产品接口
4.适用环境
- 不依赖于细节,将对象的创建和使用解耦
- 每次使用一个产品族,可通过配置文件动态改变和添加
- 同一产品组的产品在一起使用
- 系统提供一个产品类的库,所有产品以同样的接口出现
5.优点
- 隔离具体类的生成,高内聚低耦合
- 保证客户端只使用同一个产品族的对象
- 对产品族符合“开闭原则”(对产品等级结构不符合)
6.缺点
- 增加新种类产品涉及抽象工厂及其所有子类的修改
四、对比(开闭原则)
简单工厂 | 不满足 |
工厂方法 | 满足 |
抽象工厂 | 倾斜性(对产品族满足,对产品等级结构不满足) |