【西瓜带你学设计模式 | 第四期 - 抽象工厂模式】抽象工厂模式 —— 定义、核心结构、实战示例、优缺点与适用场景及模式区别

文章目录

    • 前言
    • [1. 抽象工厂模式是什么?](#1. 抽象工厂模式是什么?)
    • [2. 解决什么问题?](#2. 解决什么问题?)
      • [2.1 有多个"产品维度",并且需要成套切换](#2.1 有多个“产品维度”,并且需要成套切换)
      • [2.2 变化点分散导致代码难维护](#2.2 变化点分散导致代码难维护)
    • [3. 核心结构](#3. 核心结构)
    • [4. 示例](#4. 示例)
      • [4.1 抽象产品:Slice(切片)](#4.1 抽象产品:Slice(切片))
      • [4.2 抽象产品:Pulp(果肉)](#4.2 抽象产品:Pulp(果肉))
      • [4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉)](#4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉))
      • [4.4 抽象工厂:WatermelonFactory(声明"创建产品族"的方法)](#4.4 抽象工厂:WatermelonFactory(声明“创建产品族”的方法))
      • [4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory](#4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory)
      • [4.6 客户端使用:只依赖抽象工厂与抽象产品](#4.6 客户端使用:只依赖抽象工厂与抽象产品)
    • [5. 为什么叫"抽象工厂"](#5. 为什么叫“抽象工厂”)
    • [6. 优缺点](#6. 优缺点)
    • [7. 适用场景总结](#7. 适用场景总结)
    • [8. 与"工厂方法 / 简单工厂 / 建造者模式"的区别](#8. 与“工厂方法 / 简单工厂 / 建造者模式”的区别)
      • [8.1 抽象工厂 vs 简单工厂](#8.1 抽象工厂 vs 简单工厂)
      • [8.2 抽象工厂 vs 工厂方法](#8.2 抽象工厂 vs 工厂方法)
      • [8.3 抽象工厂 vs 建造者模式](#8.3 抽象工厂 vs 建造者模式)
    • [9. 总结](#9. 总结)

前言

抽象工厂模式(Abstract Factory) 里,我们关注的核心通常不是"只创建一个对象",而是:

创建一整套"相互关联"的对象族,并且保证它们之间的兼容性。

当你发现系统里既有"产品A的实现要切换",又有"产品B的实现也要一起跟着切换"(而且它们经常成对/成套出现),并且你希望它们在同一轮使用中保持一致性时,就很适合考虑抽象工厂模式。


1. 抽象工厂模式是什么?

抽象工厂模式 :提供一个创建抽象产品族 的接口,其中每个抽象方法负责创建一个"产品等级"的对象;具体工厂类实现这些方法来生成一整套相同风格/同一系列的具体产品。

用更直观的话说:

  • 工厂负责"生产"
  • 抽象工厂负责"生产一族产品"
  • 具体工厂负责"生产某一族具体产品"(比如一套 Theme:Win 风格 / Mac 风格)

2. 解决什么问题?

抽象工厂要解决的典型问题是:

2.1 有多个"产品维度",并且需要成套切换

例如一个 UI 系统可能同时需要:

  • 按钮(Button)
  • 输入框(Input)
  • 菜单(Menu)

如果你只用简单工厂,你可能会写出这种"局部切换但容易混搭"的逻辑:

  • 本轮 UI 想要 "Mac 风格" 的按钮
  • 却误用了 "Windows 风格" 的输入框

结果就是:不同实现组合导致风格不一致,甚至行为不兼容

2.2 变化点分散导致代码难维护

当你频繁在客户端里做 if/else 来选择具体类:

  • 代码会充满类型分支
  • 新增产品族时要改很多地方
  • 违背开闭原则(扩展要改已有逻辑)

抽象工厂的目标是:

  • 让客户端只依赖抽象工厂接口
  • 具体工厂决定生成哪一套具体产品
  • 保证同一工厂创建出来的产品彼此兼容

3. 核心结构

抽象工厂模式一般包含四类角色:

  1. 抽象产品(AbstractProduct)
    • 产品的抽象接口/抽象类(例如 Button、Input)
  2. 具体产品(ConcreteProduct)
    • 实现这些抽象接口的具体类(例如 MacButton、WinButton)
  3. 抽象工厂(AbstractFactory)
    • 声明创建一族产品的方法(创建 Button、创建 Input...)
  4. 具体工厂(ConcreteFactory)
    • 实现抽象工厂,生产某一套"同风格/同系列"的具体产品
  5. 客户端(Client)
    • 通过抽象工厂创建产品,并使用抽象产品接口
    • 不关心"具体 new 哪个类"

一句话串起来:

Client 只认 AbstractFactory;AbstractFactory 生产一整套 AbstractProduct;ConcreteFactory 决定具体是哪一族产品。


4. 示例

同一主题下的组件必须成套一致

4.1 抽象产品:Slice(切片)

java 复制代码
public interface Slice {
    void show();
}

4.2 抽象产品:Pulp(果肉)

java 复制代码
public interface Pulp {
    void show();
}

4.3 具体产品:RedSlice / OrangeSlice(切片) / RedPulp / OrangePulp(果肉)

java 复制代码
public class RedSlice implements Slice {
    @Override
    public void show() {
        System.out.println("红心西瓜:切片(红色通透、甜香)");
    }
}

public class OrangeSlice implements Slice {
    @Override
    public void show() {
        System.out.println("橙心西瓜:切片(橙红渐变、清爽)");
    }
}

public class RedPulp implements Pulp {
    @Override
    public void show() {
        System.out.println("红心西瓜:果肉(细腻红润、脆甜)");
    }
}

public class OrangePulp implements Pulp {
    @Override
    public void show() {
        System.out.println("橙心西瓜:果肉(柔软橙香、清甜)");
    }
}

4.4 抽象工厂:WatermelonFactory(声明"创建产品族"的方法)

java 复制代码
public interface WatermelonFactory {
    Slice createSlice();
    Pulp createPulp();
}

4.5 具体工厂:RedWatermelonFactory / OrangeWatermelonFactory

java 复制代码
public class RedWatermelonFactory implements WatermelonFactory {
    @Override
    public Slice createSlice() {
        return new RedSlice();
    }

    @Override
    public Pulp createPulp() {
        return new RedPulp();
    }
}

public class OrangeWatermelonFactory implements WatermelonFactory {
    @Override
    public Slice createSlice() {
        return new OrangeSlice();
    }

    @Override
    public Pulp createPulp() {
        return new OrangePulp();
    }
}

4.6 客户端使用:只依赖抽象工厂与抽象产品

java 复制代码
public class Client {
    private final Slice slice;
    private final Pulp pulp;

    public Client(WatermelonFactory factory) {
        this.slice = factory.createSlice();
        this.pulp = factory.createPulp();
    }

    public void serve() {
        slice.show();
        pulp.show();
    }

    public static void main(String[] args) {
        WatermelonFactory factory = new RedWatermelonFactory(); // 切换口味/系列,只换工厂
        Client client = new Client(factory);
        client.serve();
    }
}

关键点:客户端不需要知道 RedSlice/RedPulpOrangeSlice/OrangePulp 的具体类名,保证成套一致。


5. 为什么叫"抽象工厂"

你会发现抽象工厂不仅解决"创建对象",还解决了:

  • 多个相关对象一起创建
  • 同一套产品族之间保持一致性

这就是"抽象工厂 = 生产产品族"的根本原因。


6. 优缺点

优点

  1. 保证产品族一致性
    • 同一主题/系列生成出来的对象天然兼容
  2. 降低客户端对具体类的依赖
    • 客户端只依赖抽象工厂和抽象产品
  3. 更符合开闭原则(扩展产品族)
    • 新增一个系列(例如 Android 风格)通常只需新增一套具体工厂与具体产品
  4. 适合"多维度变化"
    • 不同产品维度(按钮/输入框/菜单)一起切换时优势明显

缺点

  1. 类会显著变多
    • 每新增一个产品族,需要新增多个具体产品 + 一个具体工厂
  2. 新增"产品等级"会更麻烦
    • 例如新增一种新组件类型(例如 Slider)意味着要扩展所有具体工厂的创建方法
  3. 结构相对复杂
    • 相比简单工厂/工厂方法,可读性要求更高

7. 适用场景总结

建议使用抽象工厂模式当你具备以下特征:

  • 你的系统需要创建多个类型的对象
  • 这些对象属于同一产品族(比如一套 UI 组件、一套数据库方言、一套操作系统风格)
  • 你希望客户端在运行时通过选择不同工厂来获得不同风格的产品族
  • 你需要保证"同族产品之间的兼容性"
  • 系统的产品族可能不断扩展(更常见)

8. 与"工厂方法 / 简单工厂 / 建造者模式"的区别

8.1 抽象工厂 vs 简单工厂

  • 简单工厂:通常只负责"创建一个等级"的产品(一个维度),用参数决定返回哪个具体类
  • 抽象工厂:负责"创建一整套产品族"(多个维度:Button + Input + ...)

一句话:

简单工厂偏"单产品";抽象工厂偏"产品族"。


8.2 抽象工厂 vs 工厂方法

  • 工厂方法(Factory Method):延迟创建到子类(一个创建维度),通常是"一个抽象产品 => 一个具体工厂创建它"
  • 抽象工厂 :一个工厂要创建多个抽象产品,并保证它们属于同一族

一句话:

工厂方法:解决"一个产品等级"的创建延迟;抽象工厂:解决"多个产品等级的成套一致"。


8.3 抽象工厂 vs 建造者模式

  • 建造者(Builder) :强调"一步步构建复杂对象",同一个对象的构建过程可变化(最终仍是一个对象)
  • 抽象工厂 :强调"创建一族相互关联的对象",更像是多个产品的生产体系

一句话:

建造者关注"构建过程";抽象工厂关注"生产产品族"。


9. 总结

抽象工厂模式通过"抽象工厂 + 具体工厂"来生产一整套相互兼容的产品族。

客户端只依赖抽象接口,避免散落的 newif/else,从而在"多维度成套切换"场景下更易维护、更稳健。

相关推荐
大数据新鸟2 小时前
设计模式详解——模板方法模式
java·tomcat·模板方法模式
always_TT2 小时前
内存泄漏是什么?如何避免?
android·java·开发语言
白鸽梦游指南2 小时前
docker仓库的工作原理及搭建仓库
java·docker·eureka
※DX3906※2 小时前
SpringBoot之旅4: MyBatis 操作数据库(进阶) 动态SQL+MyBatis-Plus实战,从入门到熟练,再也不踩绑定异常、SQL拼接坑
java·数据库·spring boot·spring·java-ee·maven·mybatis
_院长大人_2 小时前
Spring Boot 3.3 + Atomikos 分布式事务日志路径配置踩坑记录
spring boot·分布式·后端
java1234_小锋2 小时前
Java高频面试题:怎么实现Redis的高可用?
java·开发语言·redis
jiankeljx2 小时前
MySQL-mysql zip安装包配置教程
java
FlagOS智算系统软件栈2 小时前
智源×Eclipse基金会携手打造PanEval,中欧协同开启“评测+开源+合规”新模式
java·eclipse·开源
日出等日落2 小时前
用 Kavita实现我的远程数字书屋搭建记!
java·开发语言·ide·vscode·编辑器