什么是抽象工厂模式?

抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它属于创建型模式。
可以把它想象成一个“超级工厂”,这个工厂不只生产一种产品,而是生产一个产品家族 (family) 中的所有产品。例如,一个工厂可能同时生产特定主题下的按钮、文本框、复选框等所有 UI 组件。

核心思想

抽象工厂模式的核心在于定义一个抽象工厂(接口或抽象类),该工厂声明了一组用于创建不同种类抽象产品的方法。然后,创建具体的工厂类,每个具体工厂类实现这个抽象工厂,并负责实例化属于同一个特定家族(或主题) 的具体产品。
客户端代码通过抽象工厂和抽象产品的接口与对象进行交互,从而与具体的产品实现和具体工厂实现解耦。

与工厂方法模式的区别

虽然名字相似,但抽象工厂和工厂方法模式解决的问题层面不同:
  • 工厂方法模式 (Factory Method):
    • 关注点:单个产品的创建。
    • 实现方式:通常使用继承,子类重写一个工厂方法来创建特定产品。
    • 结构:一个抽象创建者和一个抽象产品,以及它们的具体子类。
  • 抽象工厂模式 (Abstract Factory):
    • 关注点:创建一族相关或相互依赖的产品
    • 实现方式:通常使用组合,客户端持有一个抽象工厂的引用。抽象工厂接口包含多个工厂方法,每个方法创建家族中的一种产品。
    • 结构:一个抽象工厂,多个抽象产品,以及它们对应的具体工厂和具体产品实现。
简单来说,工厂方法是“一个工厂方法,一个产品”,而抽象工厂是“多个工厂方法,一个产品家族”。

优点

  1. 隔离具体类 (Isolation of Concrete Classes): 客户端代码只与抽象工厂和抽象产品的接口打交道,完全不知道(也不需要知道)具体的实现类是什么,降低了耦合度。
  1. 易于交换产品系列 (Easy Exchange of Product Families): 只需要改变客户端使用的具体工厂实例,就可以轻松地切换整个产品家族(例如,从浅色主题切换到深色主题)。
  1. 保证产品兼容性 (Ensures Consistency Among Products): 由同一个具体工厂创建的产品属于同一个家族,被设计为可以协同工作。这保证了应用内产品风格或行为的一致性。
  1. 有利于扩展 (Promotes Open/Closed Principle): 增加一个新的产品家族(例如,增加一种新的 UI 主题)只需要添加新的具体工厂和具体产品类,而不需要修改现有的抽象接口或客户端代码。

使用场景

  1. 当你的系统需要独立于其产品的创建、组合和表示时。
  1. 当你的系统需要配置为由多个产品系列中的一个系列来组成时(例如,UI 主题切换)。
  1. 当你想强调一系列相关的产品对象的设计以便进行联合使用时。
  1. 当你提供一个产品类库,而只想显示它们的接口而不是实现时。
  1. Android 中的场景:
      • UI 主题切换: 最经典的场景。可以定义一个 UIFactory 接口,包含 createButton(), createTextView(), createDialog() 等方法。然后提供 MaterialLightFactory, MaterialDarkFactory, CupertinoStyleFactory 等具体工厂,分别创建对应主题风格的 UI 组件。
      • 数据库访问层切换: 如果应用需要支持多种数据库(如 SQLite, Realm, Firebase Firestore),可以定义一个 DataAccessFactory 接口,包含 createUserDao(), createOrderDao() 等方法。具体工厂如 SqliteDataAccessFactory, FirebaseDataAccessFactory 负责创建对应数据库的 DAO 实现。
      • 平台适配: 在跨平台框架或需要处理不同 Android 版本/设备特性的场景下,抽象工厂可以用来创建平台或版本相关的具体实现(例如,不同的通知管理器、权限处理器等)。

UML 图

下面是一个抽象工厂模式的 UML 结构图,以我们稍后将要实现的“UI 主题”为例:
  • UIFactory (AbstractFactory): 声明了创建抽象产品(Button, TextField)的操作接口。
  • LightThemeFactory, DarkThemeFactory (ConcreteFactory): 实现了 UIFactory 接口,负责创建具体的产品家族(浅色主题组件、深色主题组件)。
  • Button, TextField (AbstractProduct): 定义了产品家族中一类产品的接口。
  • LightButton, DarkButton, LightTextField, DarkTextField (ConcreteProduct): 实现了抽象产品接口,是具体工厂创建的目标。它们属于特定的产品家族。
  • Application (Client): 使用 UIFactoryButton/TextField 接口。它不关心具体是哪个工厂或哪个产品。

代码示例

让我们用 Kotlin 来实现上述 UI 主题的例子:
在这个例子中:
  • main 函数根据模拟的 currentTheme 获取相应的具体工厂 (LightThemeFactoryDarkThemeFactory)。
  • Application 类(客户端)接收一个 UIFactory 实例,并使用它来创建 ButtonTextField
  • 客户端完全不知道它正在使用的是 LightButton 还是 DarkButton,它只通过 Button 接口进行交互。
  • 切换主题只需要在初始化 Application 时传入不同的工厂实例即可,无需修改 Application 内部逻辑。

总结

  • 抽象工厂模式通过引入一个额外的抽象层(抽象工厂),使得创建一整套相关的产品变得容易管理和切换。
  • 它极大地增强了系统的灵活性和可扩展性,尤其是在需要支持多种“风格”或“系列”的场景下(如 UI 主题、数据库类型等)。
  • 虽然它比工厂方法模式更复杂一些(涉及更多的类和接口),但在处理产品家族时,它提供的解耦和一致性保证是非常有价值的。
设计模式——结构型-装饰器模式设计模式——创建型-工厂方法模式
Loading...