设计模式之抽象工厂模式(Abstract Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)
前言
工厂方法管单品,抽象工厂管配套。它是保证“产品族”生态一致性的标准解法,能有效杜绝组件混搭。
参考博客:抽象工厂设计模式
一、核心定义
抽象工厂模式是一种创建型设计模式,它提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
与工厂方法模式的核心区别:
- 工厂方法:一个工厂创建一种产品(如
createButton())- 抽象工厂:一个工厂创建一族产品(如
createButton()+createCheckbox())
| 关键词 | 解释 |
|---|---|
| 产品族 | 同一平台/风格下的一组产品,如 Windows 按钮 + Windows 复选框 |
| 产品等级 | 同一类型产品的不同实现,如 Windows 按钮 vs MacOS 按钮 |
| 族内一致性 | 抽象工厂保证同一工厂生产的产品一定是同一风格,不会出现 Windows 按钮配 MacOS 复选框 |
二、标准体系结构图(UML)

四个角色:抽象工厂、具体工厂、抽象产品、具体产品。客户端只依赖两层抽象。
三、场景推演:从“单品生产”到“生态全家桶”
在工厂方法模式中,我们有专门生产手机的工厂。但如果业务扩展到智能手表,客户端可能会写出这种代码:
- 从“苹果工厂”拿了 iPhone;
- 从“小米工厂”拿了 小米手表。
由于不同品牌协议不通,iPhone 无法连接小米手表,导致逻辑崩溃。我们需要一种方式,确保客户拿到的必须是同品牌的一整套产品(产品族)。
核心思想:一个工厂必须能同时生产一套相关的生态产品。
1 | // 1. 定义产品族规范 |
客户端调用:
1 | // 客户选定【苹果工厂】,产出的全系产品绝对匹配 |
简言之:抽象工厂
- 核心逻辑:强制约束具体工厂必须提供整套配套产品。
- 巨大优势:保证了产品族的一致性。从架构层面杜绝了“iPhone 配华为手表”这种逻辑错乱。
- 致命缺陷:扩展产品线(增加产品等级)极难。如果要增加“平板电脑”产线,需要修改最顶层接口,导致所有子工厂全部被迫修改,违背开闭原则。
💡 快速区分:
工厂方法:解决“如何造手机”的扩展性(加个华为手机工厂)。
抽象工厂:解决“如何造一整套手机+手表”的配套性(保证全是华为全家桶)。
四、实战案例:跨平台对话框按钮
4.1 需求分析
业务场景:开发一个跨平台 GUI 框架,需要根据操作系统渲染不同风格的 按钮(Button) 和 复选框(Checkbox):
| 平台 | 按钮 | 复选框 |
|---|---|---|
| Windows | Windowsbutton |
WindowsCheckbox |
| MacOS | MacOSButton |
MacOSCheckbox |
核心约束:同一个应用中,按钮和复选框必须是同一平台风格,不能出现 Windows 按钮 + MacOS 复选框的混搭。
代码结构:
1 | com.likerhood.design |
代码仓库: https://github.com/likerhood/CodeDesignWork#
4.2 架构图
4.2.1 面条代码架构图

4.2.2 抽象工厂架构图

4.3 类图对比
4.3.1 面条代码类图
classDiagram
class Client {
+main(args: String[]) void
}
class Application {
+paint() void
+showDialog() void
}
class MacOSButton {
+paint() void
}
class Windowsbutton {
+paint() void
}
class MacOSCheckbox {
+paint() void
}
class WindowsCheckbox {
+paint() void
}
Client --> Application : 调用
Application ..> MacOSButton : 直接依赖
Application ..> Windowsbutton : 直接依赖
Application ..> MacOSCheckbox : 直接依赖
Application ..> WindowsCheckbox : 直接依赖
style Client fill:#ffa,stroke:#333,stroke-width:2px
style Application fill:#f66,stroke:#333,stroke-width:2px
Application扇形依赖全部 4 个具体类,产品之间也没有接口约束。
4.3.2 抽象工厂类图

Application只依赖GUIFactory、Button、Checkbox三个抽象,完全不知道具体类的存在。
4.4 时序图
4.4.1 面条代码时序图
sequenceDiagram
participant Client as 客户端
participant App as Application(上帝类)
participant WinBtn as Windowsbutton
participant WinCb as WindowsCheckbox
participant MacBtn as MacOSButton
participant MacCb as MacOSCheckbox
Client->>App: paint()
App->>App: 获取 os.name
alt mac 环境
App->>MacBtn: new MacOSButton()
App->>MacCb: new MacOSCheckbox()
App->>MacBtn: paint()
App->>MacCb: paint()
else 其他环境
App->>WinBtn: new Windowsbutton()
App->>WinCb: new WindowsCheckbox()
App->>WinBtn: paint()
App->>WinCb: paint()
end
Note over App: 创建逻辑 + 业务逻辑<br/>全部混在一起
4.4.2 抽象工厂时序图
sequenceDiagram
participant Client as ClientTest
participant Factory as GUIFactory
participant ConcreteFactory as WindowsFactory
participant App as Application
participant Btn as Button实例
participant Cb as Checkbox实例
Client->>Client: configureApplication()
Client->>ConcreteFactory: new WindowsFactory()
Client->>App: new Application(factory)
App->>ConcreteFactory: createButton()
ConcreteFactory-->>App: Windowsbutton
App->>ConcreteFactory: createCheckbox()
ConcreteFactory-->>App: WindowsCheckbox
Client->>App: paint()
App->>Btn: paint()
Btn-->>App: "You have created WindowsButton."
App->>Cb: paint()
Cb-->>App: "You have created WindowsCheckbox."
Note over App: Application 全程只和<br/>抽象接口打交道
4.5 代码分析
4.5.1 抽象工厂代码
抽象产品接口:
1 | // 按钮接口 |
具体产品:
1 | // ---- Windows 产品族 ---- |
抽象工厂接口 GUIFactory:一个工厂同时负责创建一族产品
1 | public interface GUIFactory { |
具体工厂:每个工厂只生产同一风格的产品
1 | public class WindowsFactory implements GUIFactory { |
Application 类:只依赖抽象,通过构造器注入工厂
1 | public class Application { |
客户端:运行时选择工厂,注入 Application
1 | public class ClientTest { |
4.5.2 面条代码(if-else 硬编码)
如果不用抽象工厂,直接暴力写:
1 | public class Application { |
问题:
Application直接依赖所有具体产品类- 每个业务方法都要重复 if-else 判断
- 新增 Linux 平台?每个方法都要改
- 无法保证族内一致性——手抖写成
MacOSButton+WindowsCheckbox编译照样通过
总结
| 维度 | 面条代码 | 抽象工厂模式 |
|---|---|---|
| 新增平台 | 修改 Application 所有方法的 if-else | 新增一个工厂类 + 一组产品类,零修改已有代码 |
| 新增产品类型 | 在每个 if 分支里加代码 | 在 GUIFactory 接口加方法,各工厂实现 |
| 族内一致性 | ❌ 无保证,全靠程序员自觉 | ✅ 接口层面保证——同一工厂只产同族产品 |
| 依赖关系 | Application 直接依赖全部具体类 | Application 只依赖 3 个接口 |
| 开闭原则 | ❌ 违反 | ✅ 对扩展开放,对修改关闭 |
| 代码重复 | 每个方法重复 if-else | 创建逻辑集中在工厂中,业务代码无重复 |
一句话总结:抽象工厂模式将一族相关产品的创建封装在一个工厂接口背后,客户端通过切换工厂实现来一次性切换整套产品风格,既保证了族内一致性,又实现了创建与使用的彻底解耦。