1. 什么是抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是 GoF 23种设计模式中对象创建型设计模式之一,其核心思想是 把“一组相关或相互依赖的对象”的创建过程封装起来,使得客户端在不指定具体类的时候,能够获得整套产品。总的来说就是针对“产品族”而非“产品等级”进行解耦。
2.示例场景
假设你正在开发一款跨 OS 的 UI 库,需要同时支持 Windows 和 macOS。
- 产品等级:Button、CheckBox、TextField...
- 产品族:Windows 风格的一整套控件 <——> macOS 风格的一整套控件。
如果客户端代码里到处 new WinButton() / new MacButton(),未来再增加 Linux 风格就得改遍全场。抽象工厂把“整套控件”的创建动作收拢到一个工厂对象里,换皮肤=换一个工厂实例即可。
3. 角色与UML
classDiagram
direction BT
%% 抽象产品
class Button {
<<interface>>
+paint()
}
class CheckBox {
<<interface>>
+paint()
}
%% 抽象工厂
class GUIFactory {
<<interface>>
+createButton() Button
+createCheckBox() CheckBox
}
%% 具体产品
class WinButton {
+paint()
}
class MacButton {
+paint()
}
class WinCheckBox {
+paint()
}
class MacCheckBox {
+paint()
}
%% 具体工厂
class WinFactory {
+createButton() Button
+createCheckBox() CheckBox
}
class MacFactory {
+createButton() Button
+createCheckBox() CheckBox
}
%% 客户端(仅依赖抽象)
class Client {
+main(String[] args)$
}
%% 实现关系
WinButton ..|> Button
MacButton ..|> Button
WinCheckBox ..|> CheckBox
MacCheckBox ..|> CheckBox
WinFactory ..|> GUIFactory
MacFactory ..|> GUIFactory
%% 工厂创建产品(依赖)
WinFactory ..> WinButton : «create»
WinFactory ..> WinCheckBox : «create»
MacFactory ..> MacButton : «create»
MacFactory ..> MacCheckBox : «create»
%% 客户端仅依赖抽象
Client ..> GUIFactory : uses
Client ..> Button : uses
Client ..> CheckBox : uses
| 类 / 接口 | 模式中的角色 | 作用与职责 |
|---|---|---|
| Button | AbstractProduct(抽象产品) | 定义按钮这一类产品的统一接口(paint())。客户端只依赖它,而不关心具体是 Win 还是 Mac 按钮。 |
| CheckBox | AbstractProduct(抽象产品) | 定义复选框这一类产品的统一接口。同样让客户端与具体复选框解耦。 |
| WinButton | ConcreteProduct(具体产品) | Windows 风格按钮的具体实现;实现 Button 接口,负责在屏幕上真正画出 Windows 按钮。 |
| MacButton | ConcreteProduct(具体产品) | macOS 风格按钮的具体实现;实现 Button 接口,负责画出 Mac 按钮。 |
| WinCheckBox | ConcreteProduct(具体产品) | Windows 风格复选框的具体实现;实现 CheckBox 接口。 |
| MacCheckBox | ConcreteProduct(具体产品) | macOS 风格复选框的具体实现;实现 CheckBox 接口。 |
| GUIFactory | AbstractFactory(抽象工厂) | 定义创建一族产品的接口:能生产按钮,也能生产复选框。客户端只依赖它,保证同一操作系统下的产品风格一致。 |
| WinFactory | ConcreteFactory(具体工厂) | Windows 族的具体工厂;负责实例化 WinButton + WinCheckBox,保证同一窗口内所有控件都是 Windows 风格。 |
| MacFactory | ConcreteFactory(具体工厂) | macOS 族的具体工厂;负责实例化 MacButton + MacCheckBox,保证同一窗口内所有控件都是 Mac 风格。 |
| Client | Client(客户端) | 只持有抽象工厂 (GUIFactory) 与抽象产品 (Button, CheckBox) 的引用,运行时根据操作系统选择 WinFactory 或 MacFactory,从而得到一整套风格一致的控件,无需知道任何具体类。 |
4. Java代码示例
// 抽象产品
interface Button { void paint(); }
interface CheckBox { void paint(); }
// 具体产品
class WinButton implements Button { public void paint() { System.out.println("WinButton"); }}
class MacButton implements Button { public void paint() { System.out.println("MacButton"); }}
class WinCheckBox implements CheckBox { public void paint() { System.out.println("WinCheckBox"); }}
class MacCheckBox implements CheckBox { public void paint() { System.out.println("MacCheckBox"); }}
// 抽象工厂
interface GUIFactory {
Button createButton();
CheckBox createCheckBox();
}
// 具体工厂
class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public CheckBox createCheckBox() { return new WinCheckBox(); }
}
class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public CheckBox createCheckBox() { return new MacCheckBox(); }
}
// 客户端
public class Client {
public static void main(String[] args) {
String os = System.getProperty("os.name").toLowerCase();
GUIFactory factory = os.contains("win") ? new WinFactory() : new MacFactory();
Button btn = factory.createButton();
CheckBox cb = factory.createCheckBox();
btn.paint();
cb.paint();
}
}
window上运行结果
WinButton
WinCheckBox
mac上运行结果
MacButton
MacCheckBox
5. 优缺点
| 优点 | 缺点 |
|---|---|
| 隔离“产品族”的具体类,易于整体切换系列。 | 新增“产品等级”(如新增 RadioButton) 要改所有工厂接口与实现,开闭原则倾斜。 |
| 保证同一工厂产出的产品彼此兼容。 | 类数量膨胀:m 个产品等级 × n 个产品族 ≈ m×n 个类。 |
| 客户端与多态工厂交互,符合依赖倒置。 | 需要运行时注入或配置工厂,引入额外机制。 |
6. 与工厂方法模式的区别
| 维度 | 工厂方法 | 抽象工厂 |
|---|---|---|
| 关注点 | 单个产品的创建延迟到子类 | 一组(产品族)的创建延迟到子类 |
| 抽象级别 | 一个抽象产品 ↔ 一个抽象工厂方法 | 一个抽象工厂 ↔ 多个抽象产品 |
| 粒度 | 产品等级(纵向扩展) | 产品族(矩阵的“行”,横向切换) |
| 扩展性 | 新增产品等级容易:新增具体工厂子类即可 | 新增产品等级困难:需修改所有抽象与具体工厂接口 |
7. 典型应用
- JDBC 中
Connection→Statement→ResultSet整套对象的族 - Spring 的
BeanFactory族(XmlBeanFactory、AnnotationBeanFactory…)
一句话总结:抽象工厂像“主题皮肤大礼包”:换一套主题,按钮、输入框、颜色、字体瞬间全换,就像给手机换张壁纸,整机风格秒变,而你的 App 不用重启。