设计模式之抽象工厂

108 阅读3分钟

抽象工厂

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天

意图

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

说明

🥝举个栗子

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

🥝简单的说

抽象工厂模式提供了一种方法,可以封装一组具有共同特征的单个工厂,而无需指定它们的具体实现类

🥝编程示例

首先,根据上面的例子,为王国中的对象提供一些接口和实现

/**
 * 城堡接口
 */
public interface Castle {
  String getDescription();
}
/**
 * 国王接口
 */
public interface King {
  String getDescription();
}
/**
 * 军队接口
 */
public interface Army {
  String getDescription();
}
​
// 精灵具体实现 ->
public class ElfCastle implements Castle {
  static final String DESCRIPTION = "这是一个精灵的城堡!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfKing implements King {
  static final String DESCRIPTION = "这是一位精灵王!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
public class ElfArmy implements Army {
  static final String DESCRIPTION = "这是一支精灵军队!";
  @Override
  public String getDescription() {
    return DESCRIPTION;
  }
}
​
// 兽人的具体实现也类似 -> ...

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

public interface KingdomFactory {
  //给王国创建一个城堡
  Castle createCastle();
  //给王国任命一个国王
  King createKing();
  //给王国创建一支军队
  Army createArmy();
}
​
//创建精灵王国工厂的具体实现
public class ElfKingdomFactory implements KingdomFactory {
​
  @Override
  public Castle createCastle() {
    return new ElfCastle();
  }
​
  @Override
  public King createKing() {
    return new ElfKing();
  }
​
  @Override
  public Army createArmy() {
    return new ElfArmy();
  }
}
​
//创建兽人王国工厂的具体实现
public class OrcKingdomFactory implements KingdomFactory {
​
  @Override
  public Castle createCastle() {
    return new OrcCastle();
  }
​
  @Override
  public King createKing() {
    return new OrcKing();
  }
  
  @Override
  public Army createArmy() {
    return new OrcArmy();
  }
}

现在我们有了一个抽象工厂,它让我们可以创建一系列相关对象,即精灵王国工厂创建精灵城堡、国王和军队等。

var factory = new ElfKingdomFactory();
var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();
​
castle.getDescription();
king.getDescription();
army.getDescription();

程序输出

This is the elven castle!
This is the elven king!
This is the elven Army!

现在,我们可以为我们不同的王国设计工厂。在本例中,我们创建了FactoryMaker,负责返回ElfKingdomFactoryOrcKingdomFactory的实例。 客户端(调用方)可以使用FactoryMake创建所需的工厂,进而生产不同的工厂对象。 在这个例子中,我们还使用了一个枚举来参数化客户端的王国工厂的类型。

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) {
  var app = new App();
​
  LOGGER.info("开始创建精灵王国");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
  LOGGER.info(app.getArmy().getDescription());
  LOGGER.info(app.getCastle().getDescription());
  LOGGER.info(app.getKing().getDescription());
​
  LOGGER.info("开始创建兽人王国");
  app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
  -- similar use of the orc factory
}

类图

abstract-factory.urm

适用场景

  • 系统应独立于其产品的创建、组成和表示方式
  • 系统应配置多个产品系列中的一个
  • 相关产品对象需必须要在一起使用,需要保证产品一致性时
  • 您想提供产品的类库,并且只想显示它们的接口,而不是具体的实现
  • 在程序运行时,来构造特定的依赖项或调用那个产品
  • 在向程序中添加新产品或产品系列时,您不希望更改现有代码。

优点

  • 具体产品在应用层的代码隔离,无需关系创建的细节
  • 将一个系列的产品统一到一起创建

缺点

  • java中的依赖注入隐藏了服务类依赖项,这些依赖项可能会导致运行时错误在编译时就被捕获
  • 虽然在创建预定义对象时非常有用,但添加新对象(扩展新产品)可能会很复杂
  • 由于大量新接口和类与模式一起引入,增加了系统的抽象性和理解难度

其它教程

经典案例

获取源码

👉更多设计模式的源码,都整理到githup上了