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

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

4.2.2 抽象工厂架构图

4.3 类图对比
4.3.1 面条代码类图
调用
直接依赖
直接依赖
直接依赖
直接依赖
Client
+main(args: String[]) : void
Application
+paint() : void
+showDialog() : void
MacOSButton
+paint() : void
Windowsbutton
+paint() : void
MacOSCheckbox
+paint() : void
WindowsCheckbox
+paint() : void
Application扇形依赖全部 4 个具体类,产品之间也没有接口约束。
4.3.2 抽象工厂类图

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