1. 核心定义
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口(抽象工厂),而无需指定它们具体的类。它的核心是 “按‘产品族’创建对象”,而非工厂方法的 “按‘单一产品’创建对象”。
先明确两个关键概念,这是理解抽象工厂的前提:
- 产品族:指同一品牌、同一风格下的一组相关产品(如 “华为” 品牌下的 “华为手机 + 华为平板 + 华为手表”);
- 产品等级结构:指同一类型、不同品牌的产品(如 “手机” 类型下的 “华为手机 + 苹果手机 + 小米手机”)。
简单来说:工厂方法模式解决 “同一产品等级结构” 的创建(如只造手机,不管品牌);抽象工厂模式解决 “同一产品族” 的创建(如造某一品牌的全套产品,手机、平板、手表一起造)。
2. 解决的核心问题
工厂方法模式存在一个明显局限:只能创建单一类型的产品(如一个手机工厂只能造手机,无法同时造平板)。当业务需要 “批量创建一组相关联的产品” 时,工厂方法会导致工厂类爆炸(如造华为全套产品,需单独创建 “华为手机工厂 + 华为平板工厂 + 华为手表工厂”)。
抽象工厂模式的解决方案:
- 定义 “抽象工厂接口”,包含创建多个产品等级结构的方法(如
createPhone()、createTablet()); - 每个 “具体工厂” 对应一个 “产品族”,实现抽象工厂的所有方法,一次性创建该族的全套产品(如 “华为工厂” 同时实现造华为手机、华为平板的方法)。
3. 核心角色(5 个)
抽象工厂模式在工厂方法的基础上,扩展了 “产品等级结构” 的维度,核心角色如下:
| 角色名称 | 核心职责 | 示例(以 “电子设备产品族” 为例) |
|---|---|---|
| 抽象产品 A(Abstract Product A) | 定义某一产品等级结构的公共接口 | 抽象类 Phone(手机产品等级),含 call() 方法 |
| 抽象产品 B(Abstract Product B) | 定义另一产品等级结构的公共接口 | 抽象类 Tablet(平板产品等级),含 playVideo() 方法 |
| 具体产品 A1/A2(Concrete Product A1/A2) | 实现抽象产品 A,属于某一产品族 | HuaweiPhone(华为族的手机)、ApplePhone(苹果族的手机) |
| 具体产品 B1/B2(Concrete Product B1/B2) | 实现抽象产品 B,属于某一产品族 | HuaweiTablet(华为族的平板)、AppleTablet(苹果族的平板) |
| 抽象工厂(Abstract Factory) | 定义创建所有产品等级结构的接口,含多个创建方法 | 接口 DeviceFactory,含 createPhone() 和 createTablet() 方法 |
| 具体工厂 1/2(Concrete Factory 1/2) | 实现抽象工厂,对应一个产品族,创建该族的所有产品 | HuaweiFactory(造华为手机 + 华为平板)、AppleFactory(造苹果手机 + 苹果平板) |
4. 实现步骤与代码示例(Java)
以 “华为 / 苹果两大产品族的手机和平板创建” 为例,完整实现抽象工厂模式:
步骤 1:定义两个抽象产品(Phone、Tablet)
对应两个产品等级结构,规范各自的功能:
// 抽象产品A:手机(Phone)
public abstract class Phone {
// 抽象方法:打电话
public abstract void call();
// 公共方法:显示品牌(所有手机都有品牌属性)
public abstract String getBrand();
}
// 抽象产品B:平板(Tablet)
public abstract class Tablet {
// 抽象方法:播放视频
public abstract void playVideo();
// 公共方法:显示品牌
public abstract String getBrand();
}
步骤 2:实现具体产品(分 “华为族” 和 “苹果族”)
每个具体产品属于某一产品族,实现对应的抽象产品方法:
// 具体产品A1:华为手机(属于华为产品族)
public class HuaweiPhone extends Phone {
@Override
public void call() {
System.out.println(getBrand() + "手机:支持5G高清通话");
}
@Override
public String getBrand() {
return "华为";
}
}
// 具体产品B1:华为平板(属于华为产品族)
public class HuaweiTablet extends Tablet {
@Override
public void playVideo() {
System.out.println(getBrand() + "平板:支持2K分辨率视频播放");
}
@Override
public String getBrand() {
return "华为";
}
}
// 具体产品A2:苹果手机(属于苹果产品族)
public class ApplePhone extends Phone {
@Override
public void call() {
System.out.println(getBrand() + "手机:支持FaceTime通话");
}
@Override
public String getBrand() {
return "苹果";
}
}
// 具体产品B2:苹果平板(属于苹果产品族)
public class AppleTablet extends Tablet {
@Override
public void playVideo() {
System.out.println(getBrand() + "平板:支持ProRes视频录制与播放");
}
@Override
public String getBrand() {
return "苹果";
}
}
步骤 3:定义抽象工厂(DeviceFactory)
包含创建所有产品等级结构的方法(手机 + 平板):
// 抽象工厂:电子设备工厂(定义创建两个产品等级的方法)
public interface DeviceFactory {
// 创建手机(抽象产品A)
Phone createPhone();
// 创建平板(抽象产品B)
Tablet createTablet();
}
步骤 4:实现具体工厂(分 “华为工厂” 和 “苹果工厂”)
每个具体工厂对应一个产品族,实现抽象工厂的所有方法,一次性创建该族的全套产品:
// 具体工厂1:华为工厂(创建华为产品族的所有产品)
public class HuaweiFactory implements DeviceFactory {
@Override
public Phone createPhone() {
return new HuaweiPhone(); // 造华为手机
}
@Override
public Tablet createTablet() {
return new HuaweiTablet(); // 造华为平板
}
}
// 具体工厂2:苹果工厂(创建苹果产品族的所有产品)
public class AppleFactory implements DeviceFactory {
@Override
public Phone createPhone() {
return new ApplePhone(); // 造苹果手机
}
@Override
public Tablet createTablet() {
return new AppleTablet(); // 造苹果平板
}
}
步骤 5:客户端使用(按产品族创建全套产品)
客户端只需指定 “产品族”(选择具体工厂),即可一次性获取该族的所有产品,无需关注具体实现:
public class Client {
public static void main(String[] args) {
// 1. 选择产品族:这里选择“华为产品族”(切换为苹果只需改这一行)
DeviceFactory factory = new HuaweiFactory();
// DeviceFactory factory = new AppleFactory(); // 切换为苹果产品族
// 2. 按产品族创建全套产品(手机+平板)
Phone phone = factory.createPhone();
Tablet tablet = factory.createTablet();
// 3. 使用产品(无需区分具体品牌,依赖抽象产品的方法)
System.out.println("=== " + phone.getBrand() + "产品族使用 ===");
phone.call();
tablet.playVideo();
}
}
运行结果(华为工厂时) :
=== 华为产品族使用 ===
华为手机:支持5G高清通话
华为平板:支持2K分辨率视频播放
运行结果(苹果工厂时) :
=== 苹果产品族使用 ===
苹果手机:支持FaceTime通话
苹果平板:支持ProRes视频录制与播放
5. 应用场景
当业务满足以下条件时,优先使用抽象工厂模式:
- 存在多个产品族:且每个产品族包含多个相关联的产品(如 UI 组件库中的 “Windows 风格组件族”(按钮 + 输入框 + 下拉框)、“Mac 风格组件族”(对应组件));
- 客户端需统一使用某一产品族:且不希望混合使用不同产品族的产品(如开发 Windows 应用时,所有 UI 组件必须是 Windows 风格,不能混用 Mac 按钮 + Windows 输入框);
- 产品族相对稳定:新增产品族容易(加具体工厂 + 对应产品),但新增产品等级结构难(需修改抽象工厂接口,违反开闭原则)。
经典实战案例:
- 跨平台 UI 框架(如 Swing):
LookAndFeel本质是抽象工厂,WindowsLookAndFeel(Windows 产品族)创建 Windows 风格的按钮、文本框,MetalLookAndFeel(Java 默认风格)创建对应组件; - 数据库连接框架:
DataSource可视为抽象工厂,MySQLDataSource(MySQL 产品族)创建 MySQL 的Connection、Statement,OracleDataSource(Oracle 产品族)创建对应数据库对象; - 游戏开发:“角色装备族”(如 “骑士装备族” 包含骑士剑 + 骑士甲 + 骑士盾,“法师装备族” 包含法师杖 + 法师袍 + 法师帽),通过抽象工厂一次性创建某一职业的全套装备。
6. 优缺点分析
| 优点 | 缺点 |
|---|---|
| 1. 保证产品族一致性:客户端使用同一工厂创建的产品,天然属于同一族,避免混用不同族产品(如 Windows 按钮 + Mac 输入框);2. 解耦族级创建与使用:客户端只依赖抽象工厂和抽象产品,无需知道具体品牌 / 实现;3. 符合开闭原则(新增产品族):新增一个产品族,只需加 “具体工厂 + 对应产品”,无需改原有代码。 | 1. 扩展产品等级结构困难:若需新增产品(如在 “手机 + 平板” 基础上加 “手表”),需修改抽象工厂接口(加 createWatch()),所有具体工厂都要同步修改,违反开闭原则;2. 类结构复杂:相比工厂方法,抽象工厂涉及 “多产品等级 + 多产品族”,类数量更多,理解成本更高。 |
7. 与工厂方法模式的核心区别
抽象工厂和工厂方法的本质都是 “解耦创建与使用”,但适用场景完全不同,核心区别如下:
| 对比维度 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|
| 核心目标 | 创建单一产品等级结构的产品(如只造手机) | 创建多产品等级结构组成的产品族(如造手机 + 平板) |
| 抽象工厂接口 | 只含 1 个创建方法(如 createPhone()) | 含多个创建方法(如 createPhone()+createTablet()) |
| 产品族支持 | 不支持(需多个工厂才能造一个产品族) | 原生支持(1 个工厂造 1 个产品族) |
| 扩展难度 | 新增产品等级易(加具体产品 + 工厂) | 新增产品族易,新增产品等级难 |
简单总结:工厂方法是 “一对一”(1 工厂→1 产品),抽象工厂是 “一对多”(1 工厂→多产品,且多产品属同一族) 。