抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体实现类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。

图中的抽象类abstract,可以换成接口interface。
从图中可以看到,该模式主要包含以下角色:
- 抽象工厂(Abstract Factory):声明了一组用于创建产品对象的方法,每个方法对应一种产品类型。抽象工厂可以是接口或抽象类。
- 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品对象的实例。
- 抽象产品(Abstract Product):定义了一组产品对象的共同接口或抽象类,描述了产品对象的公共方法。
- 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
使用场景
- 系统独立于产品的创建、组成及表示。
- 系统配置成具有多个产品的系列,产品之间可以没有关联。
- 相关产品对象系列是共同使用的。这是抽象工厂的关键,否则可以使用工厂方法模式。
- 期望提供产品的类库,只开放其接口,而不是其实现。
代码实现
代码结构

抽象工厂
首先定义一个抽象工厂,定义工厂的生产任务。如下,我们的要求工厂可以生产A、B两种产品大类(产品族)。
public abstract class AbstractFactory {
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}抽象产品与具体产品
AbstractProductA, AbstractProductB是抽象产品,或者称为产品族。他们定义了子产品的应该具有的属性及行为。
public abstract class AbstractProductA {
public abstract void work();
}AbstractProductB定义类似AbstractProductA。
通过继承抽象产品,我们可以定义具体产品的特性。
public class ProductA1 extends AbstractProductA {
@Override
public void work() {
System.out.println("ProductA1 do something");
}
}之后我们可以创建ProductA2,ProductB1,ProductB2这样的产品。以表现产品的多样。
具体工厂
有了抽象工厂作为生产产品的要求,我们通过定义具体的工厂来实现这个目标。
考虑到环境的限制,我们往往需要多个工厂来生产不同的产品,以完成所有产品的生产任务。
public class ConcreteFactory1 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ProductB1();
}
}ConcreteFactory1只生产ProductA1,ProductB1。类似的我们定义ConcreteFactory2来生产ProductA2,ProductB2。
开始生产
我们创建一个终端,来发送生产指令。
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = produce("factory1");
AbstractProductA productA1 = factory1.createProductA();
AbstractProductB productB1 = factory1.createProductB();
productA1.work();
productB1.work();
AbstractFactory factory2 = produce("factory2");
AbstractProductA productA2 = factory2.createProductA();
AbstractProductB productB2 = factory2.createProductB();
productA2.work();
productB2.work();
}
public static AbstractFactory produce(String type) {
return switch (type) {
case "factory1" -> new ConcreteFactory1();
case "factory2" -> new ConcreteFactory2();
default -> new ConcreteFactory1();
};
}
}这里的produce方法也是一个工厂方法,用于指定具体工厂。
运行结果如下:
ProductA1 do something
ProductB1 do something
ProductA2 do something
ProductB2 do something改进
上面要想生产一个产品必须指定一个具体工厂名称。有一天新厂长来了,他不知道哪个厂生产哪个产品。根据产品来找到工厂进行生产似乎更加方便。
我们将Client调整一下,produce方法通过指定产品就能找到对应的工厂,进行生产了。
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = produce(ProductA1.class);
AbstractProductA productA1 = factory1.createProductA();
productA1.work();
AbstractFactory factory2 = produce(ProductB2.class);
AbstractProductB productB2 = factory2.createProductB();
productB2.work();
}
public static AbstractFactory produce(Class<?> type) {
if (type == ProductA1.class || type == ProductB1.class) {
return new ConcreteFactory1();
}
if (type == ProductA2.class || type == ProductB2.class) {
return new ConcreteFactory2();
}
return new ConcreteFactory1();
}
}对比工厂方法模式
工厂方法模式面向的是一个产品等级结构,每一个具体工厂创建一个产品对象。抽象工厂模式面向的时多个产品等级结构,每一个具体工厂创建一组产品对象。
当我们需要新增一个产品时,工厂方法模式需要创建一个新的工厂类;抽象工厂模式,需要在原来的抽象工厂中新增一个创建产品的方法。
与其他设计模式的对比
抽象工厂模式 vs 工厂方法模式
| 特性 | 抽象工厂模式 | 工厂方法模式 |
|---|---|---|
| 创建对象类型 | 产品家族(多个相关产品) | 单个产品 |
| 工厂接口方法 | 多个创建方法 | 一个创建方法 |
| 产品关系 | 相关或相互依赖 | 独立 |
| 扩展难度 | 难(扩展产品家族需修改抽象工厂) | 易(添加新产品只需添加新工厂) |
| 适用场景 | 多个产品等级结构的产品家族 | 单一产品等级结构 |
抽象工厂模式 vs 建造者模式
| 特性 | 抽象工厂模式 | 建造者模式 |
|---|---|---|
| 目的 | 创建产品家族 | 创建复杂对象的不同表示 |
| 构建方式 | 一次性创建完整产品 | 分步构建 |
| 关注点 | 产品家族的一致性 | 产品的构建细节 |
| 扩展性 | 产品家族扩展困难 | 构建过程和产品表示扩展容易 |
| 客户端参与度 | 低(只需选择工厂) | 高(需指导构建过程) |
抽象工厂模式 vs 原型模式
| 特性 | 抽象工厂模式 | 原型模式 |
|---|---|---|
| 创建方式 | 通过工厂创建新对象 | 通过复制现有对象创建新对象 |
| 适用场景 | 产品家族创建 | 对象复制(特别是创建成本高的对象) |
| 扩展性 | 产品种类扩展需修改工厂 | 新对象类型扩展只需实现Cloneable接口 |
| 性能 | 一般(需创建新对象) | 高(复制现有对象,避免重复初始化) |
| 实现复杂度 | 中(需定义多个产品和工厂接口) | 低(只需实现复制方法) |
总结
抽象工厂模式是一种创建型设计模式,它提供了一种方式来创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
优点
- 隔离了具体产品类的生成,客户端不需要知道具体产品类的类名
- 保证了产品家族的一致性,同一工厂创建的产品相互匹配
- 遵循开闭原则,添加新的产品家族只需添加新的工厂实现
- 实现了单一职责原则,每个工厂类只负责创建一个产品家族
缺点
- 扩展产品家族困难,需要修改抽象工厂接口和所有实现类
- 增加了系统的复杂度,需要定义多个产品接口和工厂接口
- 客户端需要知道具体的工厂类才能创建对应的产品家族
适用场景
- 系统需要独立于其产品的创建、组合和表示时
- 系统需要由多个产品系列中的一个来配置时
- 强调一系列相关产品对象的设计以便进行联合使用时
- 提供一个产品类库,而只想显示它们的接口而不是实现时
实际应用
在实际开发中,抽象工厂模式常用于:
- GUI工具包,如Swing、JavaFX等,不同的外观风格(如Windows、Mac)对应不同的产品家族
- 数据库访问层,不同的数据库(如MySQL、Oracle)对应不同的产品家族
- 操作系统相关的API,不同的操作系统提供不同的实现