Skip to content

抽象工厂方法 (Abstract Factory Pattern)

概括

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

它用于解决 一组产品族如何统一创建 的问题,并确保产品之间的一致性(比如:UI 组件中的按钮和文本框属于同一风格)。

使用场景

适合以下场景:

  • 一个系统需要使用多个“产品族”,且希望保持产品族之间的风格一致性;

  • 系统需要在运行时决定使用哪个产品族;

  • 需要对“创建一整组对象”的过程进行封装。

类图说明

plaintext
        ┌────────────────────────┐
        │   AbstractFactory      │  ← 抽象工厂:定义创建一组产品的接口
        └──────────▲─────────────┘

     ┌─────────────┴────────────┐
     │                          │
ConcreteFactoryA        ConcreteFactoryB
  (如:Mac 风格)         (如:Windows 风格)

        ┌──────────────┐          ┌──────────────┐
        │ AbstractButton│         │ AbstractTextBox│ ← 抽象产品
        └──────▲───────┘          └──────▲───────┘
               │                             │
   ┌───────────┴──────────┐     ┌────────────┴───────────┐
   │   MacButton          │     │    MacTextBox          │
   └──────────────────────┘     └────────────────────────┘
   │ WindowsButton        │     │  WindowsTextBox        │
   └──────────────────────┘     └────────────────────────┘

使用示例

我们要实现一个可以根据系统风格(Mac / Windows)生产统一风格的 UI 组件:按钮和文本框。

  1. 抽象产品接口
java
public interface Button {
    void paint();
}

public interface TextBox {
    void draw();
}
  1. 具体产品类
java
// Mac 风格
public class MacButton implements Button {
    public void paint() {
        System.out.println("绘制 Mac 风格的按钮");
    }
}

public class MacTextBox implements TextBox {
    public void draw() {
        System.out.println("绘制 Mac 风格的文本框");
    }
}

// Windows 风格
public class WindowsButton implements Button {
    public void paint() {
        System.out.println("绘制 Windows 风格的按钮");
    }
}

public class WindowsTextBox implements TextBox {
    public void draw() {
        System.out.println("绘制 Windows 风格的文本框");
    }
}
  1. 抽象工厂接口
java
public interface GUIFactory {
    Button createButton();
    TextBox createTextBox();
}
  1. 具体工厂类
java
public class MacFactory implements GUIFactory {
    public Button createButton() {
        return new MacButton();
    }

    public TextBox createTextBox() {
        return new MacTextBox();
    }
}

public class WindowsFactory implements GUIFactory {
    public Button createButton() {
        return new WindowsButton();
    }

    public TextBox createTextBox() {
        return new WindowsTextBox();
    }
}
  1. 客户端调用
java
public class Application {
    private Button button;
    private TextBox textBox;

    public Application(GUIFactory factory) {
        button = factory.createButton();
        textBox = factory.createTextBox();
    }

    public void render() {
        button.paint();
        textBox.draw();
    }

    public static void main(String[] args) {
        GUIFactory factory;

        String os = "Mac"; // 可改为 "Windows"
        if (os.equals("Mac")) {
            factory = new MacFactory();
        } else {
            factory = new WindowsFactory();
        }

        Application app = new Application(factory);
        app.render();
    }
}

优缺点分析

✅ 优点

优点说明
1. 产品族一致性抽象工厂可以保证一组相关产品(如按钮和文本框)风格一致,不会混用不兼容的产品。
2. 解耦具体类客户端只依赖接口,不依赖具体实现类,符合依赖倒置原则,方便维护和扩展。
3. 符合开闭原则添加新的产品族,只需增加一个新的具体工厂类,不影响已有代码结构。
4. 更高层的封装将产品“组”的创建过程统一封装,有利于整体构建更一致、更模块化的系统结构。

❌ 缺点

缺点说明
1. 扩展产品等级结构困难如果要在所有产品族中添加一个新产品(比如增加 Slider),必须修改所有工厂接口和所有具体工厂类,违反开闭原则。
2. 系统复杂度提高为每一个产品族都需要定义多个类(接口 + 实现 + 工厂),结构较重,不适合产品结构简单的系统
3. 灵活性差于组合抽象工厂天生强调“产品组的一致性”,但现实中有时需要不同厂商的组件混用,这种模式反而受限。

与工厂模式的区别

对比点工厂方法模式抽象工厂模式
解决问题的粒度创建一个“产品”的过程创建“一组产品”的过程
产品数量一个工厂对应一个产品一个工厂创建多个相关产品
扩展方式添加新产品:创建新工厂 + 新产品类添加新产品族:创建一组新产品类 + 新工厂类
结构复杂度中等较高,结构更复杂
例子日志系统只创建 Logger 实例UI 工厂创建 Button、TextBox 等多个组件实例

总结

抽象工厂是一种超级工厂,它不仅生产一个产品,而是生产多个相关产品对象,使得客户端能以统一的方式使用这些对象,而不需要关心其具体实现。它是实现产品“风格一致性”的利器。