抽象工厂模式

19-06-13 jdon
              

目的

提供用于创建相关或从属对象族的接口,而无需指定其具体类。

说明

要创建一个王国,我们需要具有共同主题的对象。精灵王国需要一个精灵国王,精灵城堡和精灵军队,而兽人王国需要一个兽人国王,兽人城堡和兽人军队。王国中的物体之间存在依赖关系。

简单来说

工厂的工厂,将单独但相关/依赖工厂分组在一起而不指定其具体类别的工厂。

维基百科说

抽象工厂模式提供了一种封装一组具有共同主题但没有指定其具体类的单个工厂的方法

程序示例

首先,我们为王国中的对象提供了一些接口和实现

public interface Castle {
  String getDescription();
}
public interface King {
  String getDescription();
}
public interface Army {
  String getDescription();
}

// Elven implementations ->
public class ElfCastle implements Castle {
  static final String DESCRIPTION = "This is the Elven castle!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfKing implements King {
  static final String DESCRIPTION = "This is the Elven king!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfArmy implements Army {
  static final String DESCRIPTION = "This is the Elven Army!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}

// Orcish implementations similarly...

然后,我们有了王国工厂的抽象和实现

public interface KingdomFactory {
  Castle createCastle();
  King createKing();
  Army createArmy();
}

public class ElfKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new ElfCastle();
  }
  public King createKing() {
    return new ElfKing();
  }
  public Army createArmy() {
    return new ElfArmy();
  }
}

public class OrcKingdomFactory implements KingdomFactory {
  public Castle createCastle() {
    return new OrcCastle();
  }
  public King createKing() {
    return new OrcKing();
  }
  public Army createArmy() {
    return new OrcArmy();
  }
}

现在我们有了我们的抽象工厂,让我们制作相关对象的族,即精灵王国工厂创建精灵城堡,国王和军队等。

KingdomFactory factory = new ElfKingdomFactory();
Castle castle = factory.createCastle();
King king = factory.createKing();
Army army = factory.createArmy();

castle.getDescription();  // Output: This is the Elven castle!
king.getDescription(); // Output: This is the Elven king!
army.getDescription(); // Output: This is the Elven Army!

现在,我们可以为不同的王国工厂设计工厂。在这个例子中,我们创建了FactoryMaker,负责返回ElfKingdomFactory或OrcKingdomFactory的实例。客户可以使用FactoryMaker创建所需的聚合工厂,反过来,这将生产不同的聚合对象(陆军,国王,城堡)。

public static class FactoryMaker {

  public enum KingdomType {
    ELF, ORC
  }

  public static KingdomFactory makeFactory(KingdomType type) {
    switch (type) {
      case ELF:
        return new ElfKingdomFactory();
      case ORC:
        return new OrcKingdomFactory();
      default:
        throw new IllegalArgumentException("KingdomType not supported.");
    }
  }
}

public static void main(String[] args) {
  App app = new App();

  LOGGER.info("Elf Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
  LOGGER.info(app.getArmy().getDescription());
  LOGGER.info(app.getCastle().getDescription());
  LOGGER.info(app.getKing().getDescription());

  LOGGER.info("Orc Kingdom");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
  -- similar use of the orc factory
}

适用性

何时使用抽象工厂模式

  • 系统应独立于其产品的创建,组合和表示方式
  • 系统应配置多个产品系列之一
  • 一系列相关产品对象旨在一起使用,您需要强制执行此约束
  • 你想提供一个产品类库,并且只显示它们的接口,而不是它们的实现
  • 在概念上讲,依赖项的生命周期比使用者的生命周期短。
  • 您需要一个运行时值来构造特定的依赖项
  • 您需要决定在运行时从一个系列调用哪个产品。
  • 您需要提供一个或多个仅在运行时已知的参数,然后才能解析依赖项。

用例:

  • 选择在运行时调用FileSystemAcmeService或DatabaseAcmeService或NetworkAcmeService的相应实现。
  • 单元测试用例编写变得更加容易

后果:

  • java中的依赖注入隐藏了可能导致在编译时捕获的运行时错误的服务类依赖项。