文章目录
-
- 前言
- [1. 抽象工厂模式是什么?](#1. 抽象工厂模式是什么?)
- [2. 解决什么问题?](#2. 解决什么问题?)
-
- [2.1 有多个"产品维度",并且需要成套切换](#2.1 有多个“产品维度”,并且需要成套切换)
- [2.2 变化点分散导致代码难维护](#2.2 变化点分散导致代码难维护)
- [3. 核心结构](#3. 核心结构)
- [4. 示例](#4. 示例)
-
- [4.1 抽象产品:Slice(切片)](#4.1 抽象产品:Slice(切片))
- [4.2 抽象产品:Pulp(果肉)](#4.2 抽象产品:Pulp(果肉))
- [4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉)](#4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉))
- [4.4 抽象工厂:WatermelonFactory(声明"创建产品族"的方法)](#4.4 抽象工厂:WatermelonFactory(声明“创建产品族”的方法))
- [4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory](#4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory)
- [4.6 客户端使用:只依赖抽象工厂与抽象产品](#4.6 客户端使用:只依赖抽象工厂与抽象产品)
- [5. 为什么叫"抽象工厂"](#5. 为什么叫“抽象工厂”)
- [6. 优缺点](#6. 优缺点)
- [7. 适用场景总结](#7. 适用场景总结)
- [8. 与"工厂方法 / 简单工厂 / 建造者模式"的区别](#8. 与“工厂方法 / 简单工厂 / 建造者模式”的区别)
-
- [8.1 抽象工厂 vs 简单工厂](#8.1 抽象工厂 vs 简单工厂)
- [8.2 抽象工厂 vs 工厂方法](#8.2 抽象工厂 vs 工厂方法)
- [8.3 抽象工厂 vs 建造者模式](#8.3 抽象工厂 vs 建造者模式)
- [9. 总结](#9. 总结)
前言
在 抽象工厂模式(Abstract Factory) 里,我们关注的核心通常不是"只创建一个对象",而是:
创建一整套"相互关联"的对象族,并且保证它们之间的兼容性。
当你发现系统里既有"产品A的实现要切换",又有"产品B的实现也要一起跟着切换"(而且它们经常成对/成套出现),并且你希望它们在同一轮使用中保持一致性时,就很适合考虑抽象工厂模式。

1. 抽象工厂模式是什么?
抽象工厂模式 :提供一个创建抽象产品族 的接口,其中每个抽象方法负责创建一个"产品等级"的对象;具体工厂类实现这些方法来生成一整套相同风格/同一系列的具体产品。
用更直观的话说:
- 工厂负责"生产"
- 抽象工厂负责"生产一族产品"
- 具体工厂负责"生产某一族具体产品"(比如一套 Theme:Win 风格 / Mac 风格)
2. 解决什么问题?
抽象工厂要解决的典型问题是:
2.1 有多个"产品维度",并且需要成套切换
例如一个 UI 系统可能同时需要:
- 按钮(Button)
- 输入框(Input)
- 菜单(Menu)
如果你只用简单工厂,你可能会写出这种"局部切换但容易混搭"的逻辑:
- 本轮 UI 想要 "Mac 风格" 的按钮
- 却误用了 "Windows 风格" 的输入框
结果就是:不同实现组合导致风格不一致,甚至行为不兼容。
2.2 变化点分散导致代码难维护
当你频繁在客户端里做 if/else 来选择具体类:
- 代码会充满类型分支
- 新增产品族时要改很多地方
- 违背开闭原则(扩展要改已有逻辑)
抽象工厂的目标是:
- 让客户端只依赖抽象工厂接口
- 具体工厂决定生成哪一套具体产品
- 保证同一工厂创建出来的产品彼此兼容
3. 核心结构
抽象工厂模式一般包含四类角色:
- 抽象产品(AbstractProduct)
- 产品的抽象接口/抽象类(例如 Button、Input)
- 具体产品(ConcreteProduct)
- 实现这些抽象接口的具体类(例如 MacButton、WinButton)
- 抽象工厂(AbstractFactory)
- 声明创建一族产品的方法(创建 Button、创建 Input...)
- 具体工厂(ConcreteFactory)
- 实现抽象工厂,生产某一套"同风格/同系列"的具体产品
- 客户端(Client)
- 通过抽象工厂创建产品,并使用抽象产品接口
- 不关心"具体 new 哪个类"
一句话串起来:
Client 只认 AbstractFactory;AbstractFactory 生产一整套 AbstractProduct;ConcreteFactory 决定具体是哪一族产品。
4. 示例
同一主题下的组件必须成套一致。
4.1 抽象产品:Slice(切片)
java
public interface Slice {
void show();
}
4.2 抽象产品:Pulp(果肉)
java
public interface Pulp {
void show();
}
4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉)
java
public class RedSlice implements Slice {
@Override
public void show() {
System.out.println("红心西瓜:切片(红色通透、甜香)");
}
}
public class OrangeSlice implements Slice {
@Override
public void show() {
System.out.println("橙心西瓜:切片(橙红渐变、清爽)");
}
}
public class RedPulp implements Pulp {
@Override
public void show() {
System.out.println("红心西瓜:果肉(细腻红润、脆甜)");
}
}
public class OrangePulp implements Pulp {
@Override
public void show() {
System.out.println("橙心西瓜:果肉(柔软橙香、清甜)");
}
}
4.4 抽象工厂:WatermelonFactory(声明"创建产品族"的方法)
java
public interface WatermelonFactory {
Slice createSlice();
Pulp createPulp();
}
4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory
java
public class RedWatermelonFactory implements WatermelonFactory {
@Override
public Slice createSlice() {
return new RedSlice();
}
@Override
public Pulp createPulp() {
return new RedPulp();
}
}
public class OrangeWatermelonFactory implements WatermelonFactory {
@Override
public Slice createSlice() {
return new OrangeSlice();
}
@Override
public Pulp createPulp() {
return new OrangePulp();
}
}
4.6 客户端使用:只依赖抽象工厂与抽象产品
java
public class Client {
private final Slice slice;
private final Pulp pulp;
public Client(WatermelonFactory factory) {
this.slice = factory.createSlice();
this.pulp = factory.createPulp();
}
public void serve() {
slice.show();
pulp.show();
}
public static void main(String[] args) {
WatermelonFactory factory = new RedWatermelonFactory(); // 切换口味/系列,只换工厂
Client client = new Client(factory);
client.serve();
}
}
关键点:客户端不需要知道
RedSlice/RedPulp或OrangeSlice/OrangePulp的具体类名,保证成套一致。
5. 为什么叫"抽象工厂"
你会发现抽象工厂不仅解决"创建对象",还解决了:
- 多个相关对象一起创建
- 同一套产品族之间保持一致性
这就是"抽象工厂 = 生产产品族"的根本原因。
6. 优缺点
优点
- 保证产品族一致性
- 同一主题/系列生成出来的对象天然兼容
- 降低客户端对具体类的依赖
- 客户端只依赖抽象工厂和抽象产品
- 更符合开闭原则(扩展产品族)
- 新增一个系列(例如 Android 风格)通常只需新增一套具体工厂与具体产品
- 适合"多维度变化"
- 不同产品维度(按钮/输入框/菜单)一起切换时优势明显
缺点
- 类会显著变多
- 每新增一个产品族,需要新增多个具体产品 + 一个具体工厂
- 新增"产品等级"会更麻烦
- 例如新增一种新组件类型(例如 Slider)意味着要扩展所有具体工厂的创建方法
- 结构相对复杂
- 相比简单工厂/工厂方法,可读性要求更高
7. 适用场景总结
建议使用抽象工厂模式当你具备以下特征:
- 你的系统需要创建多个类型的对象
- 这些对象属于同一产品族(比如一套 UI 组件、一套数据库方言、一套操作系统风格)
- 你希望客户端在运行时通过选择不同工厂来获得不同风格的产品族
- 你需要保证"同族产品之间的兼容性"
- 系统的产品族可能不断扩展(更常见)
8. 与"工厂方法 / 简单工厂 / 建造者模式"的区别
8.1 抽象工厂 vs 简单工厂
- 简单工厂:通常只负责"创建一个等级"的产品(一个维度),用参数决定返回哪个具体类
- 抽象工厂:负责"创建一整套产品族"(多个维度:Button + Input + ...)
一句话:
简单工厂偏"单产品";抽象工厂偏"产品族"。
8.2 抽象工厂 vs 工厂方法
- 工厂方法(Factory Method):延迟创建到子类(一个创建维度),通常是"一个抽象产品 => 一个具体工厂创建它"
- 抽象工厂 :一个工厂要创建多个抽象产品,并保证它们属于同一族
一句话:
工厂方法:解决"一个产品等级"的创建延迟;抽象工厂:解决"多个产品等级的成套一致"。
8.3 抽象工厂 vs 建造者模式
- 建造者(Builder) :强调"一步步构建复杂对象",同一个对象的构建过程可变化(最终仍是一个对象)
- 抽象工厂 :强调"创建一族相互关联的对象",更像是多个产品的生产体系
一句话:
建造者关注"构建过程";抽象工厂关注"生产产品族"。
9. 总结
抽象工厂模式通过"抽象工厂 + 具体工厂"来生产一整套相互兼容的产品族。
客户端只依赖抽象接口,避免散落的
new与if/else,从而在"多维度成套切换"场景下更易维护、更稳健。