23种设计模式之抽象工厂模式

64 阅读4分钟

1. 什么是抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是 GoF 23种设计模式中对象创建型设计模式之一,其核心思想是 把“一组相关或相互依赖的对象”的创建过程封装起来,使得客户端在不指定具体类的时候,能够获得整套产品。总的来说就是针对“产品族”而非“产品等级”进行解耦。

2.示例场景

假设你正在开发一款跨 OS 的 UI 库,需要同时支持 Windows 和 macOS。

  • 产品等级:Button、CheckBox、TextField...
  • 产品族:Windows 风格的一整套控件 <——> macOS 风格的一整套控件。

如果客户端代码里到处 new WinButton() / new MacButton(),未来再增加 Linux 风格就得改遍全场。抽象工厂把“整套控件”的创建动作收拢到一个工厂对象里,换皮肤=换一个工厂实例即可。

3. 角色与UML

classDiagram
    direction BT

    %% 抽象产品
    class Button {
        <<interface>>
        +paint()
    }
    class CheckBox {
        <<interface>>
        +paint()
    }

    %% 抽象工厂
    class GUIFactory {
        <<interface>>
        +createButton() Button
        +createCheckBox() CheckBox
    }

    %% 具体产品
    class WinButton {
        +paint()
    }
    class MacButton {
        +paint()
    }
    class WinCheckBox {
        +paint()
    }
    class MacCheckBox {
        +paint()
    }

    %% 具体工厂
    class WinFactory {
        +createButton() Button
        +createCheckBox() CheckBox
    }
    class MacFactory {
        +createButton() Button
        +createCheckBox() CheckBox
    }

    %% 客户端(仅依赖抽象)
    class Client {
        +main(String[] args)$
    }

    %% 实现关系
    WinButton ..|> Button
    MacButton ..|> Button
    WinCheckBox ..|> CheckBox
    MacCheckBox ..|> CheckBox
    WinFactory ..|> GUIFactory
    MacFactory ..|> GUIFactory

    %% 工厂创建产品(依赖)
    WinFactory ..> WinButton : «create»
    WinFactory ..> WinCheckBox : «create»
    MacFactory ..> MacButton : «create»
    MacFactory ..> MacCheckBox : «create»

    %% 客户端仅依赖抽象
    Client ..> GUIFactory : uses
    Client ..> Button : uses
    Client ..> CheckBox : uses
类 / 接口模式中的角色作用与职责
ButtonAbstractProduct(抽象产品)定义按钮这一类产品的统一接口(paint())。客户端只依赖它,而不关心具体是 Win 还是 Mac 按钮。
CheckBoxAbstractProduct(抽象产品)定义复选框这一类产品的统一接口。同样让客户端与具体复选框解耦。
WinButtonConcreteProduct(具体产品)Windows 风格按钮的具体实现;实现 Button 接口,负责在屏幕上真正画出 Windows 按钮。
MacButtonConcreteProduct(具体产品)macOS 风格按钮的具体实现;实现 Button 接口,负责画出 Mac 按钮。
WinCheckBoxConcreteProduct(具体产品)Windows 风格复选框的具体实现;实现 CheckBox 接口。
MacCheckBoxConcreteProduct(具体产品)macOS 风格复选框的具体实现;实现 CheckBox 接口。
GUIFactoryAbstractFactory(抽象工厂)定义创建一族产品的接口:能生产按钮,也能生产复选框。客户端只依赖它,保证同一操作系统下的产品风格一致。
WinFactoryConcreteFactory(具体工厂)Windows 族的具体工厂;负责实例化 WinButton + WinCheckBox,保证同一窗口内所有控件都是 Windows 风格。
MacFactoryConcreteFactory(具体工厂)macOS 族的具体工厂;负责实例化 MacButton + MacCheckBox,保证同一窗口内所有控件都是 Mac 风格。
ClientClient(客户端)只持有抽象工厂 (GUIFactory) 与抽象产品 (Button, CheckBox) 的引用,运行时根据操作系统选择 WinFactoryMacFactory,从而得到一整套风格一致的控件,无需知道任何具体类。

4. Java代码示例

// 抽象产品
interface Button { void paint(); }
interface CheckBox { void paint(); }

// 具体产品
class WinButton implements Button { public void paint() { System.out.println("WinButton"); }}
class MacButton implements Button { public void paint() { System.out.println("MacButton"); }}
class WinCheckBox implements CheckBox { public void paint() { System.out.println("WinCheckBox"); }}
class MacCheckBox implements CheckBox { public void paint() { System.out.println("MacCheckBox"); }}

// 抽象工厂
interface GUIFactory {
    Button createButton();
    CheckBox createCheckBox();
}

// 具体工厂
class WinFactory implements GUIFactory {
    public Button createButton() { return new WinButton(); }
    public CheckBox createCheckBox() { return new WinCheckBox(); }
}
class MacFactory implements GUIFactory {
    public Button createButton() { return new MacButton(); }
    public CheckBox createCheckBox() { return new MacCheckBox(); }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        String os = System.getProperty("os.name").toLowerCase();
        GUIFactory factory = os.contains("win") ? new WinFactory() : new MacFactory();

        Button btn = factory.createButton();
        CheckBox cb = factory.createCheckBox();
        btn.paint();
        cb.paint();
    }
}

window上运行结果

WinButton
WinCheckBox

mac上运行结果

MacButton
MacCheckBox

5. 优缺点

优点缺点
隔离“产品族”的具体类,易于整体切换系列。新增“产品等级”(如新增 RadioButton) 要改所有工厂接口与实现,开闭原则倾斜。
保证同一工厂产出的产品彼此兼容。类数量膨胀:m 个产品等级 × n 个产品族 ≈ m×n 个类。
客户端与多态工厂交互,符合依赖倒置。需要运行时注入或配置工厂,引入额外机制。

6. 与工厂方法模式的区别

维度工厂方法抽象工厂
关注点单个产品的创建延迟到子类一组(产品族)的创建延迟到子类
抽象级别一个抽象产品 ↔ 一个抽象工厂方法一个抽象工厂 ↔ 多个抽象产品
粒度产品等级(纵向扩展)产品族(矩阵的“行”,横向切换)
扩展性新增产品等级容易:新增具体工厂子类即可新增产品等级困难:需修改所有抽象与具体工厂接口

7. 典型应用

  • JDBC 中 Connection → Statement → ResultSet 整套对象的族
  • Spring 的 BeanFactory 族(XmlBeanFactoryAnnotationBeanFactory…)

一句话总结:抽象工厂像“主题皮肤大礼包”:换一套主题,按钮、输入框、颜色、字体瞬间全换,就像给手机换张壁纸,整机风格秒变,而你的 App 不用重启。