文章

抽象工厂模式 (Abstract Factory Pattern) 深度解析

抽象工厂模式 (Abstract Factory Pattern) 深度解析

🔩 抽象工厂模式 (Abstract Factory Pattern) 深度解析

1. 模式动机与定义

1.1. 模式动机:面对多个产品等级结构

在工厂方法模式中,一个具体工厂只负责生产一个产品等级结构中的一种具体产品。但有时候,一个工厂需要提供多个产品对象,这些产品位于不同的产品等级结构中,但它们之间是相关或相互依赖的。

为了更清晰地理解抽象工厂模式,我们先回顾两个核心概念:

  • 产品等级结构 (Product Hierarchy):产品的继承结构。例如:抽象电视机 $\rightarrow$ (海尔电视机, TCL电视机)。
  • 产品族 (Product Family):由同一个工厂生产的,位于不同产品等级结构中的一组相关产品。例如:海尔工厂生产的 (海尔电视机, 海尔电冰箱)。

抽象工厂模式适用于:当系统所提供的工厂所需生产的具体产品是多个位于不同产品等级结构中属于不同类型的具体产品时。它是所有工厂模式中最为抽象和最具一般性的一种形态。

1.2. 模式定义

抽象工厂模式 (Abstract Factory Pattern)

提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。

抽象工厂模式又称为 Kit 模式,属于对象创建型模式

1.3. 区别:工厂方法 vs. 抽象工厂

特点工厂方法模式抽象工厂模式
产品数量针对一个产品等级结构中的单一产品。针对多个产品等级结构中的一组产品族
抽象度较低。最高,最具一般性。
工厂方法抽象工厂中通常只有一个 factoryMethod()抽象工厂中通常有多个 createProductX() 方法。

2. 模式结构与角色

抽象工厂模式的关键在于,一个具体工厂可以创建分属于不同产品等级结构的一个产品族中的所有对象。

2.1. 模式角色

角色名称职责描述
AbstractFactory (抽象工厂)声明生成抽象产品的方法,用于创建不同等级结构的产品。
ConcreteFactory (具体工厂)实现了抽象工厂声明的方法,生成一组具体产品,这些产品构成了一个产品族
AbstractProduct (抽象产品)为每种产品等级结构声明接口(例如:电视机电冰箱)。
ConcreteProduct (具体产品)定义具体工厂生产的具体产品对象,实现抽象产品接口(例如:海尔电视机)。

3. 代码深度解析(多产品族创建)

我们以跨平台 UI 组件为例,创建两个产品等级结构:ButtonTextField

  • 产品等级结构 1AbstractButton $\rightarrow$ (WinButton, MacButton)
  • 产品等级结构 2AbstractTextField $\rightarrow$ (WinTextField, MacTextField)
  • 产品族 1WinFactory 生产 (WinButton, WinTextField)
  • 产品族 2MacFactory 生产 (MacButton, MacTextField)

3.1. Java 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// --- 1. 抽象产品等级结构 ---
// 产品等级结构 A: Button
interface AbstractButton {
    void paint();
}
// 产品等级结构 B: TextField
interface AbstractTextField {
    void display();
}

// --- 2. 具体产品 ---
class WinButton implements AbstractButton {
    @Override public void paint() { System.out.println("Win Button painted."); }
}
class MacButton implements AbstractButton {
    @Override public void paint() { System.out.println("Mac Button painted."); }
}
class WinTextField implements AbstractTextField {
    @Override public void display() { System.out.println("Win TextField displayed."); }
}
class MacTextField implements AbstractTextField {
    @Override public void display() { System.out.println("Mac TextField displayed."); }
}

// --- 3. 抽象工厂 (声明创建产品族的方法) ---
interface AbstractFactory {
    AbstractButton createButton();
    AbstractTextField createTextField();
}

// --- 4. 具体工厂 (创建某一产品族) ---
class WinFactory implements AbstractFactory {
    @Override
    public AbstractButton createButton() { return new WinButton(); }
    @Override
    public AbstractTextField createTextField() { return new WinTextField(); }
}
class MacFactory implements AbstractFactory {
    @Override
    public AbstractButton createButton() { return new MacButton(); }
    @Override
    public AbstractTextField createTextField() { return new MacTextField(); }
}

// --- 5. 客户端 (Client) ---
public class AbstractFactoryDemo {
    public static void main(String[] args) {
        // 客户端只需要切换具体的工厂实例,即可切换整个产品族(界面主题)
        AbstractFactory factory = new WinFactory();
        AbstractButton btn = factory.createButton();
        AbstractTextField txt = factory.createTextField();
        
        System.out.println("--- Using Windows Theme ---");
        btn.paint();   // Win Button painted.
        txt.display(); // Win TextField displayed.
        
        factory = new MacFactory(); // 切换产品族
        btn = factory.createButton();
        txt = factory.createTextField();
        
        System.out.println("\n--- Using macOS Theme ---");
        btn.paint();   // Mac Button painted.
        txt.display(); // Mac TextField displayed.
    }
}

4. 模式优点、缺点与扩展

4.1. 优点

  1. 保证产品族一致性:能够保证客户端始终只使用同一个产品族中的对象,产品族中的多个对象被设计成一起工作。
  2. 隔离具体类:隔离了具体类的生成,客户并不需要知道什么被创建,更换一个具体工厂就变得相对容易。
  3. 增加产品族方便:增加新的具体工厂和产品族非常方便,无须修改抽象工厂或客户端代码,符合“开闭原则”。

4.2. 缺点:开闭原则的倾斜性

抽象工厂模式的最大的缺点在于增加新的产品等级结构非常困难

  • 增加产品族:只需增加新的 ConcreteFactory,系统对扩展开放
  • 增加产品等级结构:如果要增加一个新的产品(例如 Checkbox)到所有主题中,则需要:
    1. 修改 AbstractFactory 接口,增加 createCheckbox() 方法。
    2. 修改所有的 ConcreteFactory 子类,实现新的 createCheckbox() 方法。

这种性质称为**“开闭原则”的倾斜性**:它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供方便。

4.3. 模式扩展与退化

  • 工厂模式的退化
    • 当抽象工厂模式中每一个具体工厂类只创建一个产品对象(只存在一个产品等级结构)时,抽象工厂模式退化成工厂方法模式
    • 当工厂方法模式退化时(只有一个具体工厂且方法静态),则退化成简单工厂模式

4.4. 适用环境

  1. 系统中有多于一个的产品族,而每次只使用其中某一产品族(如不同皮肤、不同操作系统组件)。
  2. 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  3. 系统不应当依赖于产品类实例如何被创建、组合和表达的细节。
本文由作者按照 CC BY 4.0 进行授权