抽象工厂模式:产品族创建
FreeGuideOnline
最新
2026-06-18
抽象工厂模式:一站式创建产品族
在软件开发中,我们经常需要创建一系列相关或相互依赖的对象,并且希望客户端代码与具体类的实例化过程解耦。抽象工厂模式正是为了解决这类“产品族”创建问题而生,它提供一个接口,用于创建一系列相关或依赖对象的家族,而不需要显式指定它们的具体类。
认识产品族与产品等级结构
在深入抽象工厂之前,需要理解两个关键概念:
- 产品等级结构:即产品的继承结构。例如,一个抽象类是“按钮”,其子类有“Windows按钮”、“Mac按钮”,这就构成了一个产品等级。
- 产品族:由同一个工厂生产的、位于不同产品等级结构中的一组产品。例如,一个“Windows风格工厂”既生产“Windows按钮”也生产“Windows复选框”,这些产品就属于同一个产品族。
抽象工厂模式的核心思想就是将产品族的创建集中到一个独立的工厂接口中,客户端只需要与抽象工厂和抽象产品交互,无需关心具体工厂和具体产品的实现细节。
模式结构与角色
抽象工厂模式通常包含以下四个角色:
| 角色 | 职责 |
|---|---|
| 抽象工厂 (Abstract Factory) | 声明一组用于创建抽象产品对象的方法,每个方法对应一个产品等级。 |
| 具体工厂 (Concrete Factory) | 实现抽象工厂中声明的创建方法,生成具体产品族的对象。 |
| 抽象产品 (Abstract Product) | 为构成产品族的每种产品声明接口。 |
| 具体产品 (Concrete Product) | 实现抽象产品接口,由对应的具体工厂创建。 |
这些角色协作完成产品族的创建,其类图结构如下(文字描述):
- 抽象工厂接口(如
GUIFactory)包含创建按钮、创建复选框等方法。 - 具体工厂类(如
WinFactory、MacFactory)分别实现该接口,返回对应风格的具体产品。 - 抽象产品类(如
Button、Checkbox)定义了产品应有的行为。 - 具体产品类(如
WinButton、MacButton)实现了抽象产品,并代表了特定风格的产品。
动手实现:跨平台的UI组件工厂
假设我们要开发一套支持不同操作系统风格的UI组件,包括按钮(Button)和复选框(Checkbox)。每个操作系统(如 Windows 和 Mac)都有自己的一套组件风格,它们构成了两个产品族。
第一步:定义抽象产品接口
// 按钮抽象产品
public interface Button {
void paint();
}
// 复选框抽象产品
public interface Checkbox {
void paint();
}
第二步:为每个产品等级创建具体产品
// Windows风格按钮
public class WinButton implements Button {
@Override
public void paint() {
System.out.println("渲染一个Windows风格的按钮");
}
}
// Mac风格按钮
public class MacButton implements Button {
@Override
public void paint() {
System.out.println("渲染一个Mac风格的按钮");
}
}
// Windows风格复选框
public class WinCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("渲染一个Windows风格的复选框");
}
}
// Mac风格复选框
public class MacCheckbox implements Checkbox {
@Override
public void paint() {
System.out.println("渲染一个Mac风格的复选框");
}
}
第三步:声明抽象工厂接口
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
第四步:实现具体工厂(每个产品族一个工厂)
// 生产Windows风格组件的工厂
public class WinFactory implements GUIFactory {
@Override
public Button createButton() {
return new WinButton();
}
@Override
public Checkbox createCheckbox() {
return new WinCheckbox();
}
}
// 生产Mac风格组件的工厂
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public Checkbox createCheckbox() {
return new MacCheckbox();
}
}
第五步:客户端代码与具体工厂解耦
客户端仅依赖抽象工厂和抽象产品。这样,切换操作系统风格只需更换具体工厂实例即可,完全不影响应用逻辑。
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();
}
}
// 使用示例
public class Demo {
public static void main(String[] args) {
// 读取配置或通过环境判断选择具体工厂
GUIFactory factory;
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
factory = new WinFactory();
} else {
factory = new MacFactory();
}
Application app = new Application(factory);
app.paint();
}
}
运行结果(假设运行在 Windows 环境下):
渲染一个Windows风格的按钮
渲染一个Windows风格的复选框
抽象工厂模式的优点
- 分离接口与实现:客户端只与抽象接口打交道,具体实现类可以被灵活替换。
- 保证产品族内产品的一致性:一旦选定具体工厂,该工厂创建的所有产品都自然属于同一个风格,避免了混淆。
- 易于交换产品族:只需更改具体工厂的实例,整个应用的行为即可切换到另一套产品族。
- 符合开闭原则:增加新的产品族(如添加 Linux 风格)时,只需新增具体工厂和具体产品类,无需修改已有代码。
抽象工厂模式的缺点与权衡
- 增加新的产品等级结构比较困难:如果需要为每个工厂增加一种新产品(比如新增“滚动条”),就必须修改抽象工厂接口以及所有具体工厂类,这违反了开闭原则。因此,抽象工厂适合产品族相对稳定的场景。
- 系统复杂度增加:引入了众多的接口和类,对于简单对象创建可能显得过度设计。
与其他创建型模式的区别
- 与工厂方法模式:工厂方法模式只负责创建一种产品,每次增加新产品只需创建新的工厂子类;抽象工厂则负责创建一族产品。抽象工厂的内部通常使用工厂方法来实现每个产品的创建。
- 与建造者模式:建造者模式关注一步步构建复杂对象,并允许分步构建与表示分离;抽象工厂则着重于一下创建完整的产品族。
典型应用场景
- 跨平台UI工具包:如前面示例,需要为不同操作系统提供风格统一的组件家族。
- 数据库访问层:一个抽象工厂可以定义创建连接、命令、适配器等数据库相关对象的方法,具体工厂则对应 MySQL、Oracle 等数据库产品族。
- 游戏中的不同主题或等级场景:如战争游戏中,一个抽象工厂可以生产不同时代的兵种(士兵、坦克、飞机),具体工厂分别生产古代、现代、未来风格的兵种。
总结
抽象工厂模式通过为产品族的创建提供统一接口,使得客户端可以轻松地在不同的产品族之间切换,并确保同一产品族内的对象保持风格一致。掌握该模式的关键在于识别出系统中的产品等级与产品族,并在产品族相对稳定、产品等级可能增删的情况下权衡使用。当你面临“一系列相关对象需要一起创建”的需求时,抽象工厂模式将是一个强大且优雅的选择。