抽象工厂模式是一种创建型设计模式,它为创建一组相关或相互依赖的对象提供一个接口,而无需指定它们的具体类,其核心在于管理"产品族"。该模式通过抽象层隔离了具体类的实例化过程,使得系统可以在不修改客户端代码的情况下,切换整个产品系列。
一、模式结构与核心角色
抽象工厂模式主要包含四种角色,它们共同构成了模式的骨架。
| 角色 | 职责 | 说明 |
|---|---|---|
| 抽象工厂 (AbstractFactory) | 声明一组用于创建抽象产品对象的方法。 | 定义创建产品族的接口,每个方法对应一个产品等级结构。 |
| 具体工厂 (ConcreteFactory) | 实现抽象工厂的接口,负责创建属于特定产品族的具体产品对象。 | 一个具体工厂生产的产品构成一个完整的产品族。 |
| 抽象产品 (AbstractProduct) | 为每种产品声明接口。 | 定义一类产品的公共行为。 |
| 具体产品 (ConcreteProduct) | 实现抽象产品接口,定义由具体工厂创建的具体对象。 | 具体工厂创建的具体实例。 |
其UML类图关系可简述为:客户端(Client)仅依赖于AbstractFactory和AbstractProduct接口。ConcreteFactory实现AbstractFactory,并负责实例化对应的ConcreteProduct。ConcreteProduct则实现各自的AbstractProduct接口。
二、深入解析:产品族与产品等级结构
理解抽象工厂模式的关键在于厘清 "产品族" 和 "产品等级结构" 这两个概念。
- 产品等级结构:指产品的抽象与具体实现之间的继承关系。例如,"按钮"是一个抽象产品,其具体实现有"Windows按钮"和"Mac按钮",它们构成了一个产品等级结构。
- 产品族:指由同一个具体工厂创建的、分属于不同产品等级结构的一组产品。例如,由"Windows工厂"创建的"Windows按钮"和"Windows文本框"就构成了一个产品族(Windows风格族)。
抽象工厂模式就是围绕一个产品族来工作的。一个具体工厂负责生产一个产品族中的所有产品,从而保证了这些产品之间的兼容性。
三、完整代码示例:电子设备产品族
下面通过一个生产手机和电脑的电子设备产品族示例,完整展示抽象工厂模式的实现。
java
// 1. 抽象产品:手机
interface Phone {
void makeCall();
void sendMessage();
}
// 2. 抽象产品:电脑
interface Computer {
void coding();
void playGame();
}
// 3. 具体产品:小米手机
class XiaomiPhone implements Phone {
@Override
public void makeCall() {
System.out.println("使用小米手机打电话。");
}
@Override
public void sendMessage() {
System.out.println("使用小米手机发短信。");
}
}
// 4. 具体产品:小米电脑
class XiaomiComputer implements Computer {
@Override
public void coding() {
System.out.println("在小米笔记本上写代码。");
}
@Override
public void playGame() {
System.out.println("用小米电脑玩游戏。");
}
}
// 5. 具体产品:华为手机
class HuaweiPhone implements Phone {
@Override
public void makeCall() {
System.out.println("使用华为手机打电话。");
}
@Override
public void sendMessage() {
System.out.println("使用华为手机发短信。");
}
}
// 6. 具体产品:华为电脑
class HuaweiComputer implements Computer {
@Override
public void coding() {
System.out.println("在华为MateBook上写代码。");
}
@Override
public void playGame() {
System.out.println("用华为电脑玩游戏。");
}
}
// 7. 抽象工厂:电子设备工厂
interface ElectronicFactory {
Phone createPhone();
Computer createComputer();
}
// 8. 具体工厂:小米工厂
class XiaomiFactory implements ElectronicFactory {
@Override
public Phone createPhone() {
return new XiaomiPhone(); // 生产小米手机
}
@Override
public Computer createComputer() {
return new XiaomiComputer(); // 生产小米电脑
}
}
// 9. 具体工厂:华为工厂
class HuaweiFactory implements ElectronicFactory {
@Override
public Phone createPhone() {
return new HuaweiPhone(); // 生产华为手机
}
@Override
public Computer createComputer() {
return new HuaweiComputer(); // 生产华为电脑
}
}
// 10. 客户端应用
public class Client {
private Phone myPhone;
private Computer myComputer;
// 客户端通过抽象工厂接口构建产品族
public Client(ElectronicFactory factory) {
this.myPhone = factory.createPhone();
this.myComputer = factory.createComputer();
}
public void useDevices() {
System.out.println("开始使用设备:");
myPhone.makeCall();
myPhone.sendMessage();
myComputer.coding();
myComputer.playGame();
}
public static void main(String[] args) {
// 模拟根据配置或用户选择决定品牌
String brand = "Huawei"; // 可动态配置
ElectronicFactory factory;
if ("Xiaomi".equalsIgnoreCase(brand)) {
factory = new XiaomiFactory(); // 创建小米产品族
} else {
factory = new HuaweiFactory(); // 创建华为产品族
}
Client customer = new Client(factory);
customer.useDevices();
// 当 brand = "Huawei" 时输出:
// 开始使用设备:
// 使用华为手机打电话。
// 使用华为手机发短信。
// 在华为MateBook上写代码。
// 用华为电脑玩游戏。
}
}
四、模式的优缺点与适用场景
优点:
- 保证产品兼容性:一个具体工厂创建的所有产品都属于同一产品族,它们被设计为能协同工作,避免了不匹配的问题。
- 符合开闭原则(对扩展开放):当需要增加一个新的产品族(如增加一个"苹果工厂")时,只需新增对应的具体工厂和具体产品类,无需修改现有抽象工厂和客户端代码。
- 符合单一职责原则:将产品创建代码集中到一个地方,使得代码易于维护。
- 符合依赖倒置原则:客户端代码只依赖于抽象接口(抽象工厂和抽象产品),不依赖于具体类。
缺点:
- 难以支持新种类的产品(违反开闭原则对修改关闭) :这是该模式最显著的缺点。如果需要在所有产品族中增加一个全新的产品种类(例如,在
ElectronicFactory中增加createTablet()方法来生产平板电脑),就必须修改ElectronicFactory接口,这会导致所有具体工厂类都需要随之修改。 - 系统复杂性增加:引入了大量的接口和类,对于小型项目可能显得过于繁重。
适用场景:
| 场景 | 说明 |
|---|---|
| 系统需要独立于产品的创建、组合和表示 | 如跨平台UI库、不同数据库的访问驱动等。 |
| 系统需要配置多个产品族中的一个来使用 | 如选择使用一套完整的"现代风格"或"古典风格"家具。 |
| 一系列相关的产品对象需要被设计为一起使用 | 强调产品间的约束关系,确保客户端使用的是一套兼容的产品。 |
| 希望提供一个产品类库,只暴露接口 | 隐藏具体实现,向客户端提供抽象的创建接口。 |
五、与工厂方法模式的对比
工厂方法模式与抽象工厂模式经常被混淆,下表清晰地展示了两者的核心区别:
| 对比维度 | 工厂方法模式 (Factory Method) | 抽象工厂模式 (Abstract Factory) |
|---|---|---|
| 核心焦点 | 创建单个产品对象。 | 创建一系列相关或依赖的产品对象(产品族)。 |
| 工厂职责 | 一个工厂类只负责创建一种具体产品。 | 一个工厂类负责创建一整个产品族(包含多种产品)。 |
| 扩展方向 | 易于支持新的产品类型(新增产品等级结构),只需新增产品类和对应的工厂子类。 | 易于支持新的产品族 (新增具体工厂),但难以支持新的产品种类(需修改抽象工厂接口)。 |
| 结构复杂度 | 相对简单。 | 更为复杂。 |
| 关系 | 可以看作是抽象工厂模式的一种特例(只生产一种产品的抽象工厂)。抽象工厂通常使用多个工厂方法来实现。 |
在实际框架中,抽象工厂模式有广泛应用。例如,在Java的JDBC中,Connection和Statement就是抽象产品,而DriverManager.getConnection()根据不同的数据库驱动返回不同的具体工厂(连接),从而创建出与特定数据库兼容的一系列对象(如Oracle的Statement或MySQL的Statement)。在MyBatis中,SqlSessionFactory也是一个典型的抽象工厂,它负责创建SqlSession、Executor等一组相关的对象。