抽象工厂设计模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)

前言

工厂方法管单品,抽象工厂管配套。它是保证"产品族"生态一致性的标准解法,能有效杜绝组件混搭。

参考博客:抽象工厂设计模式


一、核心定义

抽象工厂模式 是一种创建型设计模式,它提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。

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

  • 工厂方法:一个工厂创建一种 产品(如 createButton()
  • 抽象工厂:一个工厂创建一族 产品(如 createButton() + createCheckbox()
关键词 解释
产品族 同一平台/风格下的一组产品,如 Windows 按钮 + Windows 复选框
产品等级 同一类型产品的不同实现,如 Windows 按钮 vs MacOS 按钮
族内一致性 抽象工厂保证同一工厂生产的产品一定是同一风格,不会出现 Windows 按钮配 MacOS 复选框

二、标准体系结构图(UML)

四个角色:抽象工厂、具体工厂、抽象产品、具体产品。客户端只依赖两层抽象。


三、场景推演:从"单品生产"到"生态全家桶"

在工厂方法模式中,我们有专门生产手机的工厂。但如果业务扩展到智能手表,客户端可能会写出这种代码:

  • 从"苹果工厂"拿了 iPhone
  • 从"小米工厂"拿了 小米手表

由于不同品牌协议不通,iPhone 无法连接小米手表 ,导致逻辑崩溃。我们需要一种方式,确保客户拿到的必须是同品牌的一整套产品(产品族)

核心思想:一个工厂必须能同时生产一套相关的生态产品。

Java 复制代码
// 1. 定义产品族规范
public interface AbstractFactory {
    Phone createPhone(); // 产线1:手机
    Watch createWatch(); // 产线2:手表
}

// 2. 具体的品牌全能代工厂
public class AppleFactory implements AbstractFactory {
    @Override
    public Phone createPhone() { return new IPhone(); }
    @Override
    public Watch createWatch() { return new AppleWatch(); }
}

public class HuaweiFactory implements AbstractFactory {
    @Override
    public Phone createPhone() { return new HuaweiPhone(); }
    @Override
    public Watch createWatch() { return new HuaweiWatch(); }
}

客户端调用:

Java 复制代码
// 客户选定【苹果工厂】,产出的全系产品绝对匹配
AbstractFactory factory = new AppleFactory();
Phone phone = factory.createPhone(); // 拿到 iPhone
Watch watch = factory.createWatch(); // 拿到 AppleWatch

简言之:抽象工厂

  • 核心逻辑 :强制约束具体工厂必须提供整套配套产品
  • 巨大优势 :保证了产品族的一致性。从架构层面杜绝了"iPhone 配华为手表"这种逻辑错乱。
  • 致命缺陷扩展产品线(增加产品等级)极难。如果要增加"平板电脑"产线,需要修改最顶层接口,导致所有子工厂全部被迫修改,违背开闭原则。

💡 快速区分:

工厂方法:解决"如何造手机"的扩展性(加个华为手机工厂)。

抽象工厂:解决"如何造一整套手机+手表"的配套性(保证全是华为全家桶)。


四、实战案例:跨平台对话框按钮

4.1 需求分析

业务场景 :开发一个跨平台 GUI 框架,需要根据操作系统渲染不同风格的 按钮(Button)复选框(Checkbox)

平台 按钮 复选框
Windows Windowsbutton WindowsCheckbox
MacOS MacOSButton MacOSCheckbox

核心约束 :同一个应用中,按钮和复选框必须是同一平台风格,不能出现 Windows 按钮 + MacOS 复选框的混搭。

代码结构

复制代码
com.likerhood.design
├── buttons/                    # 产品族A - 按钮
│   ├── Button.java             # 抽象产品接口
│   ├── MacOSButton.java        # MacOS 按钮
│   └── Windowsbutton.java      # Windows 按钮
├── checkboxes/                 # 产品族B - 复选框
│   ├── Checkbox.java           # 抽象产品接口
│   ├── MacOSCheckbox.java      # MacOS 复选框
│   └── WindowsCheckbox.java    # Windows 复选框
├── factories/                  # 工厂层
│   ├── GUIFactory.java         # 抽象工厂接口
│   ├── MacOSFactory.java       # MacOS 工厂
│   └── WindowsFactory.java     # Windows 工厂

代码仓库: https://github.com/likerhood/CodeDesignWork#

4.2 架构图

4.2.1 面条代码架构图
4.2.2 抽象工厂架构图

4.3 类图对比

4.3.1 面条代码类图

调用
直接依赖
直接依赖
直接依赖
直接依赖
Client
+main(args: String[]) : void
Application
+paint() : void
+showDialog() : void
MacOSButton
+paint() : void
Windowsbutton
+paint() : void
MacOSCheckbox
+paint() : void
WindowsCheckbox
+paint() : void

Application 扇形依赖全部 4 个具体类,产品之间也没有接口约束。

4.3.2 抽象工厂类图

Application 只依赖 GUIFactoryButtonCheckbox 三个抽象,完全不知道具体类的存在。

4.4 时序图

4.4.1 面条代码时序图

MacOSCheckbox MacOSButton WindowsCheckbox Windowsbutton Application(上帝类) 客户端 MacOSCheckbox MacOSButton WindowsCheckbox Windowsbutton Application(上帝类) 客户端 alt [mac 环境] [其他环境] 创建逻辑 + 业务逻辑 全部混在一起 paint() 获取 os.name new MacOSButton() new MacOSCheckbox() paint() paint() new Windowsbutton() new WindowsCheckbox() paint() paint()

4.4.2 抽象工厂时序图

Checkbox实例 Button实例 Application WindowsFactory GUIFactory ClientTest Checkbox实例 Button实例 Application WindowsFactory GUIFactory ClientTest Application 全程只和 抽象接口打交道 configureApplication() new WindowsFactory() new Application(factory) createButton() Windowsbutton createCheckbox() WindowsCheckbox paint() paint() "You have created WindowsButton." paint() "You have created WindowsCheckbox."

4.5 代码分析

4.5.1 抽象工厂代码

抽象产品接口

java 复制代码
// 按钮接口
public interface Button {
    void paint();
}

// 复选框接口
public interface Checkbox {
    void paint();
}

具体产品

java 复制代码
// ---- Windows 产品族 ----
public class Windowsbutton implements Button {
    public void paint() {
        System.out.println("You have created WindowsButton.");
    }
}

public class WindowsCheckbox implements Checkbox {
    public void paint() {
        System.out.println("You have created WindowsCheckbox.");
    }
}

// ---- MacOS 产品族 ----
public class MacOSButton implements Button {
    public void paint() {
        System.out.println("You have created MacOSButton.");
    }
}

public class MacOSCheckbox implements Checkbox {
    public void paint() {
        System.out.println("You have created MacOSCheckbox.");
    }
}

抽象工厂接口 GUIFactory:一个工厂同时负责创建一族产品

java 复制代码
public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

具体工厂 :每个工厂只生产同一风格的产品

java 复制代码
public class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new Windowsbutton();
    }
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

public class MacOSFactory implements GUIFactory {
    public Button createButton() {
        return new MacOSButton();
    }
    public Checkbox createCheckbox() {
        return new MacOSCheckbox();
    }
}

Application 类:只依赖抽象,通过构造器注入工厂

java 复制代码
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();
    }
}

客户端:运行时选择工厂,注入 Application

java 复制代码
public class ClientTest {
    private static Application configureApplication() {
        GUIFactory factory;
        String osName = System.getProperty("os.name").toLowerCase();
        if (osName.contains("mac")) {
            factory = new MacOSFactory();
        } else {
            factory = new WindowsFactory();
        }
        return new Application(factory);
    }

    public static void main(String[] args) {
        Application app = configureApplication();
        app.paint();
    }
}
4.5.2 面条代码(if-else 硬编码)

如果不用抽象工厂,直接暴力写:

java 复制代码
public class Application {

    public void paint() {
        String osName = System.getProperty("os.name").toLowerCase();

        if (osName.contains("mac")) {
            MacOSButton button = new MacOSButton();
            MacOSCheckbox checkbox = new MacOSCheckbox();
            button.paint();
            checkbox.paint();
        } else {
            Windowsbutton button = new Windowsbutton();
            WindowsCheckbox checkbox = new WindowsCheckbox();
            button.paint();
            checkbox.paint();
        }
    }

    // 如果还有其他业务方法要用到这些组件...
    public void showDialog() {
        String osName = System.getProperty("os.name").toLowerCase();
        // 再来一遍一模一样的 if-else...
        if (osName.contains("mac")) {
            MacOSButton btn = new MacOSButton();
            MacOSCheckbox cb = new MacOSCheckbox();
            // ...
        } else {
            Windowsbutton btn = new Windowsbutton();
            WindowsCheckbox cb = new WindowsCheckbox();
            // ...
        }
    }
}

问题

  1. Application 直接依赖所有具体产品类
  2. 每个业务方法都要重复 if-else 判断
  3. 新增 Linux 平台?每个方法都要改
  4. 无法保证族内一致性------手抖写成 MacOSButton + WindowsCheckbox 编译照样通过

总结

维度 面条代码 抽象工厂模式
新增平台 修改 Application 所有方法的 if-else 新增一个工厂类 + 一组产品类,零修改已有代码
新增产品类型 在每个 if 分支里加代码 GUIFactory 接口加方法,各工厂实现
族内一致性 ❌ 无保证,全靠程序员自觉 ✅ 接口层面保证------同一工厂只产同族产品
依赖关系 Application 直接依赖全部具体类 Application 只依赖 3 个接口
开闭原则 ❌ 违反 ✅ 对扩展开放,对修改关闭
代码重复 每个方法重复 if-else 创建逻辑集中在工厂中,业务代码无重复

一句话总结 :抽象工厂模式将一族相关产品的创建封装在一个工厂接口背后,客户端通过切换工厂实现来一次性切换整套产品风格,既保证了族内一致性,又实现了创建与使用的彻底解耦。

相关推荐
sg_knight19 小时前
设计模式实战:命令模式(Command)
python·设计模式·命令模式
渔舟小调1 天前
P11 | 收藏与行程:用户行为类接口的设计模式
数据库·设计模式·oracle
小程故事多_801 天前
从基础Agent到复杂工作流,LangGraph如何用状态机重构智能体开发
人工智能·设计模式·重构·aigc·ai编程
hypoy1 天前
Claude Code 的 1M Context 怎么用:一篇官方文章的读后整理
设计模式·claude
IT 行者1 天前
软件设计模式会不会是制约大模型编程的障碍?
设计模式·ai编程
t***5441 天前
还有哪些设计模式适合现代C++
开发语言·c++·设计模式
t***5441 天前
如何在现代C++项目中有效应用这些设计模式
开发语言·c++·设计模式
贵慜_Derek1 天前
我们能从 DeerFlow 学到哪些优秀的技术架构设计
人工智能·设计模式·架构
Q741_1471 天前
设计模式之装饰器模式 理论总结 C++代码实战
c++·设计模式·装饰器模式
无籽西瓜a1 天前
【西瓜带你学设计模式 | 第十八期 - 命令模式】命令模式 —— 请求封装与撤销实现、优缺点与适用场景
java·后端·设计模式·软件工程·命令模式