抽象工厂模式是什么?

抽象工厂模式(Abstract Factory Pattern)是一种创建型的设计模式。根据 GoF 对抽象工厂模式的定义:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

即抽象工厂提供一个接口用于创建一系列相关或者依赖的对象,而无需指定它们的具体类。
何为一系列相关或者依赖的对象?举一个简单的例子:手机与其配件,诸如耳机、数据线、适配器等。一般来说,每家厂商生产的手机与其配件都是配套的。如果你要去手机店购买一部苹果手机,那么你肯定希望附属的配件也是苹果的,而非小米或者华为等其他厂商的。
怎么理解抽象工厂只提供一组接口用于创建对象,而无需指定它们的具体的类呢?仍然以手机为例,假设现在有一家物流公司负责运输手机厂商制造的产品到手机商城进行售卖。对于物流公司而言,它需要依赖厂商生产的手机,但它其实并不用关注手机是哪家厂商生产的,也不用关注手机是哪种类型。

UML 类图

用 UML 类图来描述抽象工厂模式的结构,在模式中各个角色之间的关系:
image.png
根据上图,总结了模式中各个角色的职责以及它们之间的关系:

  • 抽象产品是一组不同但相关的产品,它们构成了一个产品家族。
  • 具体产品是这组抽象产品的多种实现,可按主题对这些变体分组。
  • 抽象工厂声明了一组创建各种抽象产品的方法。
  • 具体工厂则实现了抽象工厂的创建方法。每个具体的工厂都与特定变体的产品相对应,并且只创建这种产品变体。
  • 客户端只需要通过抽象工厂来创建抽象产品,而不用关注具体的工厂和产品。那么由谁负责创建实际的工厂对象呢?一般情况下,应用程序会在初始化阶段创建具体的工厂对象,而在此之前,应用程序必须能够根据配置文件或者环境设定选择特定的工厂类型。

案例

让我们通过一个案例来帮助我们理解工厂方法模式。假设有如下情景:在手机商场中,展示着各大厂商生产的手机及其配件以供顾客体验,手机的种类繁多,有 iPhone、小米手机、华为手机等。
借助上述的模式结构,我们先梳理一下情景中的各个角色。首先,手机及其配件是一组相关的抽象产品。

  1. public abstract class Phone {
  2. protected String name;
  3. protected String verion;
  4. protected Color color;
  5. private Earphones earphones;
  6. // getters and setters
  7. public Phone(String verion, Color color) {
  8. this.verion = verion;
  9. this.color = color;
  10. }
  11. public void display() {
  12. // Our code for displaying the phone.
  13. }
  14. // other methods
  15. }
  16. public abstract class Earphones {
  17. private Color color;
  18. // getters and setters
  19. public Earphones(Color color) {
  20. this.color = color;
  21. }
  22. // other methods
  23. }

各厂商生产的手机及其配件则是这组相关产品的具体实现。以苹果产品的变体为例,小米、华为等产品变体则不再赘述。

  1. public class IPhone extends Phone {
  2. public IPhone(String verion, Color color) {
  3. super(verion, color);
  4. this.name = "iPhone";
  5. }
  6. }
  7. public class AppleEarpods extends Earphones {
  8. public AppleEarpods(Color color) {
  9. super(color);
  10. }
  11. }

抽象工厂这一角色是手机厂商,它声明了一组接口来创建这一族相关的产品:手机及其配件,至于生产的是何种变体的产品,则由具体的手机厂商来控制。

  1. public abstract class PhoneFactory {
  2. public abstract Phone createPhone(String version, Color color);
  3. public abstract Earphones createEarphones(Color color);
  4. public void assemblePhone(Phone phone, Earphones earphones) {
  5. if (phone != null && earphones != null) {
  6. phone.setEarphones(earphones);
  7. }
  8. }
  9. }

对于苹果变体的产品,由苹果厂商负责创建:

  1. public class AppleFactory extends PhoneFactory {
  2. @Override
  3. public Phone createPhone(String version, Color color) {
  4. return new IPhone(version, color);
  5. }
  6. @Override
  7. public Earphones createEarphones(Color color) {
  8. return new AppleEarpods(color);
  9. }
  10. }

而小米变体的产品,则由小米厂商负责创建:

  1. public class XiaomiFactory extends PhoneFactory {
  2. @Override
  3. public Phone createPhone(String version, Color color) {
  4. return new XiaomiPhone(version, color);
  5. }
  6. @Override
  7. public Earphones createEarphones(Color color) {
  8. return new XiaomiEarphones(color);
  9. }
  10. }

最后,我们通过一个用例来模拟一下客户端:应用程序通过程序启动参数选择手机厂商的种类,并以此创建和展示该品牌的手机。

  1. public class AbstractFactoryMain {
  2. public static void main(String[] args) {
  3. if (args == null || args.length < 3) {
  4. throw new IllegalArgumentException("Failed to parse the arguments.");
  5. }
  6. String factoryType = args[0];
  7. String version = args[1];
  8. Color color = Color.get(args[2]);
  9. PhoneFactory phoneFactory;
  10. if ("Apple".equalsIgnoreCase(factoryType)) {
  11. phoneFactory = new AppleFactory();
  12. } else if ("Xiaomi".equalsIgnoreCase(factoryType)) {
  13. phoneFactory = new XiaomiFactory();
  14. } else {
  15. throw new IllegalArgumentException("Unknown Phone Factory.");
  16. }
  17. Phone phone = phoneFactory.createPhone(version, color);
  18. Earphones earphones = phoneFactory.createEarphones(color);
  19. phoneFactory.assemblePhone(phone, earphones);
  20. phone.display();
  21. }
  22. }

案例源码

可在 GitHub 上查看上述案例的完整代码。

参考资料

本文参考的资料如下: