第 3 天:抽象工厂模式(Abstract Factory Pattern)—— 创建型模式

138 阅读8分钟

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. 应用场景

当业务满足以下条件时,优先使用抽象工厂模式:

  1. 存在多个产品族:且每个产品族包含多个相关联的产品(如 UI 组件库中的 “Windows 风格组件族”(按钮 + 输入框 + 下拉框)、“Mac 风格组件族”(对应组件));
  2. 客户端需统一使用某一产品族:且不希望混合使用不同产品族的产品(如开发 Windows 应用时,所有 UI 组件必须是 Windows 风格,不能混用 Mac 按钮 + Windows 输入框);
  3. 产品族相对稳定:新增产品族容易(加具体工厂 + 对应产品),但新增产品等级结构难(需修改抽象工厂接口,违反开闭原则)。

经典实战案例

  • 跨平台 UI 框架(如 Swing):LookAndFeel 本质是抽象工厂,WindowsLookAndFeel(Windows 产品族)创建 Windows 风格的按钮、文本框,MetalLookAndFeel(Java 默认风格)创建对应组件;
  • 数据库连接框架:DataSource 可视为抽象工厂,MySQLDataSource(MySQL 产品族)创建 MySQL 的 ConnectionStatementOracleDataSource(Oracle 产品族)创建对应数据库对象;
  • 游戏开发:“角色装备族”(如 “骑士装备族” 包含骑士剑 + 骑士甲 + 骑士盾,“法师装备族” 包含法师杖 + 法师袍 + 法师帽),通过抽象工厂一次性创建某一职业的全套装备。

6. 优缺点分析

优点缺点
1. 保证产品族一致性:客户端使用同一工厂创建的产品,天然属于同一族,避免混用不同族产品(如 Windows 按钮 + Mac 输入框);2. 解耦族级创建与使用:客户端只依赖抽象工厂和抽象产品,无需知道具体品牌 / 实现;3. 符合开闭原则(新增产品族):新增一个产品族,只需加 “具体工厂 + 对应产品”,无需改原有代码。1. 扩展产品等级结构困难:若需新增产品(如在 “手机 + 平板” 基础上加 “手表”),需修改抽象工厂接口(加 createWatch()),所有具体工厂都要同步修改,违反开闭原则;2. 类结构复杂:相比工厂方法,抽象工厂涉及 “多产品等级 + 多产品族”,类数量更多,理解成本更高。

7. 与工厂方法模式的核心区别

抽象工厂和工厂方法的本质都是 “解耦创建与使用”,但适用场景完全不同,核心区别如下:

对比维度工厂方法模式抽象工厂模式
核心目标创建单一产品等级结构的产品(如只造手机)创建多产品等级结构组成的产品族(如造手机 + 平板)
抽象工厂接口只含 1 个创建方法(如 createPhone()含多个创建方法(如 createPhone()+createTablet()
产品族支持不支持(需多个工厂才能造一个产品族)原生支持(1 个工厂造 1 个产品族)
扩展难度新增产品等级易(加具体产品 + 工厂)新增产品族易,新增产品等级难

简单总结:工厂方法是 “一对一”(1 工厂→1 产品),抽象工厂是 “一对多”(1 工厂→多产品,且多产品属同一族)