抽象工厂模式(Abstract Factory Pattern)
定义
抽象工厂模式是一种创建型设计模式,提供一组相关或依赖对象的创建接口,而无需指定具体类。它强调创建产品族(一组相关联的产品),例如不同操作系统的 UI 组件(按钮、文本框等),或不同数据库的驱动适配器。
UML 类图
- AbstractFactory(抽象工厂):声明创建一组产品的接口(如 createProductA() 和 createProductB())。
- ConcreteFactory(具体工厂):实现抽象工厂接口,创建属于同一产品族的具体产品(如 ConcreteFactory1 创建 ProductA1 和 ProductB1)。
- AbstractProduct(抽象产品):定义一类产品的接口(如 AbstractProductA 和 AbstractProductB)。
- ConcreteProduct(具体产品):实现抽象产品接口的具体类(如 ConcreteProductA1 属于产品族 1)。
优点
- 产品族一致性:确保创建的对象属于同一系列(例如同一操作系统下的所有 UI 组件)。
- 客户端与实现解耦:客户端代码仅依赖抽象接口,不依赖具体类。
- 开闭原则:新增产品族时,只需添加新的具体工厂和产品类,无需修改已有代码。
- 单一职责原则:每个工厂类只负责创建特定产品族。
缺点
- 扩展新产品类型困难:若需在已有产品族中添加新类型(如新增 AbstractProductC),需修改所有抽象工厂和具体工厂,违反开闭原则。
- 类数量膨胀:每新增一个产品族需新增多个类(工厂 + 产品),增加系统复杂度。
- 理解成本高:多层抽象和依赖关系对新手不够友好。
适用场景
- 跨平台应用:需要为不同操作系统(如 Windows、macOS)生成配套的 UI 组件或服务。
- 数据库适配器:为不同数据库(MySQL、PostgreSQL)创建连接、查询等兼容对象。
- 主题系统:提供一套主题相关的组件(如暗黑/明亮主题的按钮、字体、颜色)。
- 产品族约束:要求一组对象必须一起使用,且需屏蔽具体实现细节。
案例
UML 类图
Factory
ComputerProductFactory
Product
KeyboardProduct
MouseProduct
LenovoComputerProductFactory
LenovoKeyboardProduct
LenovoMouseProduct
LogitechComputerProductFactory
LogitechKeyboardProduct
LogitechMouseProduct
Client
抽象工厂模式 vs 工厂方法模式
对比维度 | 抽象工厂模式 | 工厂方法模式 |
---|---|---|
核心目标 | 创建多个相关产品族(如跨平台UI组件套件) | 创建单个产品类型(如不同格式的日志记录器) |
产品结构 | 包含多个产品等级结构(如Button +TextBox ) | 仅一个产品等级结构(如Document ) |
产品关系 | 强调产品间的兼容性(必须属于同一系列) | 不要求产品间有关联性 |
工厂职责 | 一个工厂创建多种产品(多方法) | 一个工厂创建一种产品(单方法) |
扩展方向 | 扩展产品族容易(新增ConcreteFactory )扩展产品类型困难(需改接口) | 扩展产品类型容易(新增ConcreteCreator ) |
适用场景 | 需要保证产品兼容性(如操作系统、主题套件) | 需要灵活扩展单一产品类型(如文件格式) |
类数量复杂度 | 高(工厂+多产品类) | 低(工厂+单产品类) |
开闭原则 | 对新增产品族开放,对新增产品类型关闭 | 对新增产品类型开放 |
关键差异总结
-
目标不同
- 抽象工厂:解决多系列产品兼容性问题(如 Windows/macOS 整套组件)。
- 工厂方法:解决单一产品多态化创建问题(如 PDF/Word 文档生成)。
-
扩展性差异
- 抽象工厂新增产品族时只需添加新工厂类(如
MacOSFactory
),但新增产品类型需修改所有工厂接口。 - 工厂方法新增产品类型时只需添加新子类(如
ExcelDocument
),无需修改已有代码。
- 抽象工厂新增产品族时只需添加新工厂类(如
-
复杂度差异
- 抽象工厂需要管理多个产品层级,适合中大型系统。
- 工厂方法结构简单,适合单一产品扩展场景。
选择建议
- 使用抽象工厂:当系统需要一组相互依赖的对象(如 UI 组件 + 字体 + 颜色)。
- 使用工厂方法:当系统需要灵活扩展单一产品类型(如不同数据库驱动)。