Appearance
抽象工厂模式(Abstract Factory Pattern)
1. 官方定义
"Provide an interface for creating families of related or dependent objects without specifying their concrete classes."
—— 《Design Patterns: Elements of Reusable Object-Oriented Software》(GoF, 1994)
核心:提供一个接口,用于创建一组相关或依赖的对象,而无需指定它们的具体类。
2. 模式解释
核心思想
- 产品族(Product Family):一组相互关联或依赖的对象(例如 GUI 中的按钮、文本框、滚动条需风格统一)。
- 抽象工厂:定义创建产品族的接口,具体工厂负责实现该接口以生成特定风格的产品。
- 客户端解耦:客户端仅依赖抽象工厂和抽象产品接口,不感知具体实现。
典型结构
plaintext
|<<Interface>>|
AbstractFactory
△
| implements
|
┌──────────────┴──────────────┐
| |
ConcreteFactoryA ConcreteFactoryB
| |
createProduct1() → ProductA1 createProduct1() → ProductB1
createProduct2() → ProductA2 createProduct2() → ProductB2
|<<Interface>>| |<<Interface>>|
Product1 Product2
△ △
| implements | implements
| |
ProductA1 ──────────────── ProductA2
ProductB1 ──────────────── ProductB2
优点
- 一致性保证:确保同一产品族中的对象协同工作(如 Windows 风格的所有组件)。
- 开闭原则支持:新增产品族时只需扩展新工厂,无需修改已有代码。
- 客户端简化:客户端代码仅依赖抽象接口,与具体实现解耦。
缺点
- 扩展产品类型困难:新增产品类型(如新增一个
Product3
)需修改所有工厂接口和实现类。 - 复杂度高:需预先设计完善的产品族结构,否则易过度设计。
3. 解决的问题
经典场景
- 跨平台 UI 组件
- 为 Windows、Mac、Linux 提供风格统一的按钮(
Button
)、文本框(TextBox
)。
- 为 Windows、Mac、Linux 提供风格统一的按钮(
- 数据库访问抽象
- 支持 MySQL、Oracle 等数据库的
Connection
、Command
、Adapter
组件的兼容创建。
- 支持 MySQL、Oracle 等数据库的
- 系统换肤功能
- 切换主题时,确保所有 UI 元素(颜色、字体、图标)风格一致。
4. 实现注意事项
关键实现点
- 产品族定义
- 明确哪些对象属于同一产品族(如
Button
+TextBox
属于 UI 组件族)。
- 明确哪些对象属于同一产品族(如
- 接口设计
- 抽象工厂接口需声明所有产品类型的创建方法(如
createButton()
,createTextBox()
)。
- 抽象工厂接口需声明所有产品类型的创建方法(如
- 产品兼容性
- 确保同一工厂创建的对象能协同工作(如 Windows 工厂生产的按钮不能与 Mac 文本框混用)。
- 配置管理
- 通过配置文件、环境变量或依赖注入(如 Spring)动态选择具体工厂(如
WindowsFactory
vsMacFactory
)。
- 通过配置文件、环境变量或依赖注入(如 Spring)动态选择具体工厂(如
代码片段示例
java
// 抽象产品族
interface Button { void render(); }
interface TextBox { void input(); }
// 具体产品(Windows 风格)
class WindowsButton implements Button { /* ... */ }
class WindowsTextBox implements TextBox { /* ... */ }
// 抽象工厂
interface GUIFactory {
Button createButton();
TextBox createTextBox();
}
// 具体工厂(Windows)
class WindowsFactory implements GUIFactory {
public Button createButton() { return new WindowsButton(); }
public TextBox createTextBox() { return new WindowsTextBox(); }
}
5. 实现变体
两种常见实现方式
类型 | 特点 | 适用场景 |
---|---|---|
标准抽象工厂 | 每个产品族对应一个具体工厂类(如 WindowsFactory 、MacFactory ) | 产品族类型固定且明确 |
动态工厂(参数化) | 通过参数选择产品族(如 createUIComponent("Windows") ) | 产品族类型由外部条件动态决定(需注意违反 OCP 的风险) |
6. 相似模式对比
模式 | 核心区别 |
---|---|
工厂方法模式 | 关注创建单一产品,而抽象工厂模式创建一组相关产品 |
建造者模式 | 分步骤构建复杂对象,抽象工厂直接返回完整对象组 |
原型模式 | 通过克隆生成对象,抽象工厂通过工厂方法生成对象 |
7. 组合使用场景
常见搭配模式
- 单例模式
- 场景:确保具体工厂类全局唯一(如数据库工厂只需一个实例)。
- 组合方式:将
ConcreteFactory
实现为单例。
- 原型模式
- 场景:快速生成复杂产品族的副本(如游戏中的地图模板生成器)。
- 组合模式
- 场景:统一处理产品族中的复杂结构(如 UI 容器中包含多个组件)。
8. 总结记忆点
- 核心价值:为相关对象组提供统一创建的抽象层。
- 一句话区分工厂方法 vs 抽象工厂:
- 工厂方法:1 个工厂 → 1 个产品
- 抽象工厂:1 个工厂 → N 个关联产品
- 适用性判断:当系统需要多维度切换产品组合时优先考虑(如同时切换操作系统和 UI 主题)。