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

四个角色:抽象工厂、具体工厂、抽象产品、具体产品。客户端只依赖两层抽象。
三、场景推演:从“单品生产”到“生态全家桶”
在工厂方法模式中,我们有专门生产手机的工厂。但如果业务扩展到智能手表,客户端可能会写出这种代码:
- 从“苹果工厂”拿了 iPhone;
- 从“小米工厂”拿了 小米手表。
由于不同品牌协议不通,iPhone 无法连接小米手表,导致逻辑崩溃。我们需要一种方式,确保客户拿到的必须是同品牌的一整套产品(产品族)。
核心思想:一个工厂必须能同时生产一套相关的生态产品。
// 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(); }
}
客户端调用:
// 客户选定【苹果工厂】,产出的全系产品绝对匹配
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 面条代码类图
Application扇形依赖全部 4 个具体类,产品之间也没有接口约束。
4.3.2 抽象工厂类图

Application只依赖GUIFactory、Button、Checkbox三个抽象,完全不知道具体类的存在。
4.4 时序图
4.4.1 面条代码时序图
4.4.2 抽象工厂时序图
4.5 代码分析
4.5.1 抽象工厂代码
抽象产品接口:
// 按钮接口
public interface Button {
void paint();
}
// 复选框接口
public interface Checkbox {
void paint();
}
具体产品:
// ---- 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:一个工厂同时负责创建一族产品
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
具体工厂:每个工厂只生产同一风格的产品
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 类:只依赖抽象,通过构造器注入工厂
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
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 硬编码)
如果不用抽象工厂,直接暴力写:
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 | 创建逻辑集中在工厂中,业务代码无重复 |
一句话总结:抽象工厂模式将一族相关产品的创建封装在一个工厂接口背后,客户端通过切换工厂实现来一次性切换整套产品风格,既保证了族内一致性,又实现了创建与使用的彻底解耦。
&spm=1001.2101.3001.5002&articleId=160192273&d=1&t=3&u=9a32f96b0f0b4e7db52f63cc8481b6cb)
2333

被折叠的 条评论
为什么被折叠?



