文章目录
-
- [1. 引言:当工厂方法还不够用时](#1. 引言:当工厂方法还不够用时)
- [2. 什么是抽象工厂模式](#2. 什么是抽象工厂模式)
-
- [GoF 定义](#GoF 定义)
- [3. 抽象工厂模式的核心思想:产品族](#3. 抽象工厂模式的核心思想:产品族)
- [4. 抽象工厂模式的角色组成](#4. 抽象工厂模式的角色组成)
- [5. 示例场景:跨平台 UI 组件库](#5. 示例场景:跨平台 UI 组件库)
- [6. 抽象产品定义](#6. 抽象产品定义)
- [7. 具体产品实现](#7. 具体产品实现)
-
- [Windows 系列产品](#Windows 系列产品)
- [Mac 系列产品](#Mac 系列产品)
- [8. 抽象工厂接口](#8. 抽象工厂接口)
- [9. 具体工厂实现](#9. 具体工厂实现)
-
- [Windows 工厂](#Windows 工厂)
- [Mac 工厂](#Mac 工厂)
- [10. 客户端使用方式](#10. 客户端使用方式)
- [11. 抽象工厂模式的优点](#11. 抽象工厂模式的优点)
- [12. 抽象工厂模式的缺点](#12. 抽象工厂模式的缺点)
- [13. 抽象工厂 vs 工厂方法](#13. 抽象工厂 vs 工厂方法)
- [14. JDK 与框架中的应用](#14. JDK 与框架中的应用)
- [15. 适用场景总结](#15. 适用场景总结)
- 参考

1. 引言:当工厂方法还不够用时
在前面的文章【设计模式】工厂方法模式(Factory Method)详解:从简单工厂到真正的"面向扩展"-CSDN博客 ,已经介绍了:
- 简单工厂模式:用一个工厂 + if-else 创建对象
- 工厂方法模式:一个产品对应一个工厂,符合开闭原则
但在实际项目中,我们常常遇到更复杂的场景:
系统需要创建的不是一个对象,而是一整套"相互关联、相互依赖"的对象。
例如:
- 不同风格的 UI 组件(按钮 + 文本框 + 菜单)
- 不同数据库的访问组件(Connection + Statement + ResultSet)
- 不同操作系统下的一组系统组件
这时,如果还使用工厂方法模式,就会出现工厂数量爆炸、客户端组合复杂的问题。
为了解决这个问题,就引出了------抽象工厂模式。
如果你发现"创建对象总是成套出现",那就该用抽象工厂模式了。
2. 什么是抽象工厂模式
GoF 定义
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
一句话理解:
抽象工厂 = 工厂的工厂,用来创建"产品族"。
【设计模式】工厂方法模式介绍的工厂方法模式中考虑的是一类产品的生产,比如牧场只养动物、手机厂只生产手机等。
这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族。
3. 抽象工厂模式的核心思想:产品族
理解抽象工厂模式,关键在于产品族(Product Family)。
什么是产品族?
在同一个业务场景下,必须一起使用的一组产品。
例如 UI 场景:
| 产品族 | 按钮 | 文本框 |
|---|---|---|
| Windows 风格 | WinButton | WinTextBox |
| Mac 风格 | MacButton | MacTextBox |
👉 同一行是一组产品族(Windows产品族、Mac产品组)
👉 同一列是同一产品等级结构
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
4. 抽象工厂模式的角色组成
抽象工厂模式通常包含五个角色:
- 抽象工厂(AbstractFactory)
:提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
- 具体工厂(ConcreteFactory)
主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品 A
抽象产品定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 抽象产品 B
- 具体产品 A / B
实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
5. 示例场景:跨平台 UI 组件库
假设我们要开发一个 UI 库,支持:
- Windows 风格
- Mac 风格
组件包括:
- Button(按钮)
- TextBox(文本框)
6. 抽象产品定义
Button
java
public interface Button {
void render();
}
TextBox
java
public interface TextBox {
void input();
}
7. 具体产品实现
Windows 系列产品
java
public class WinButton implements Button {
@Override
public void render() {
System.out.println("渲染 Windows 风格按钮");
}
}
java
public class WinTextBox implements TextBox {
@Override
public void input() {
System.out.println("Windows 风格文本框输入");
}
}
Mac 系列产品
java
public class MacButton implements Button {
@Override
public void render() {
System.out.println("渲染 Mac 风格按钮");
}
}
java
public class MacTextBox implements TextBox {
@Override
public void input() {
System.out.println("Mac 风格文本框输入");
}
}
8. 抽象工厂接口
java
public interface UIFactory {
Button createButton();
TextBox createTextBox();
}
9. 具体工厂实现
Windows 工厂
java
public class WindowsUIFactory implements UIFactory {
@Override
public Button createButton() {
return new WinButton();
}
@Override
public TextBox createTextBox() {
return new WinTextBox();
}
}
Mac 工厂
java
public class MacUIFactory implements UIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
}
10. 客户端使用方式
java
public class Client {
private Button button;
private TextBox textBox;
public Client(UIFactory factory) {
this.button = factory.createButton();
this.textBox = factory.createTextBox();
}
public void renderUI() {
button.render();
textBox.input();
}
}
客户端代码的特点:
- 完全依赖抽象
- 不关心具体产品类
- 切换产品族只需切换工厂
11. 抽象工厂模式的优点
- 保证产品族的一致性(当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象)
- 客户端与具体产品彻底解耦
- 符合开闭原则(对产品族扩展友好)
- 非常适合框架和中间件开发
12. 抽象工厂模式的缺点
- 不利于扩展新的产品等级结构
例如:
- 现在只有 Button + TextBox
- 如果新增
CheckBox
👉 所有工厂都要修改(当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改)。
- 代码结构复杂,类数量多
13. 抽象工厂 vs 工厂方法
| 维度 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 创建对象数量 | 单个 | 一组 |
| 关注点 | 产品 | 产品族 |
| 扩展方向 | 新产品 | 新产品族 |
| 系统复杂度 | 中 | 高 |
14. JDK 与框架中的应用
JDBC
java
Connection conn = DriverManager.getConnection(...);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(...);
- 一整套数据库访问对象
- 不同数据库 = 不同产品族
15. 适用场景总结
适合使用
- 系统需要多套产品组合
- 强调产品之间的协作关系
- 框架级、平台级系统
不适合使用
- 产品结构经常变化
- 产品种类非常少
- 项目规模较小