外观模式(Facade)


意图
为子系统中的一组接口提供统一接口。Facade定义了一个更高级别的接口,使子系统更易于使用。
解释
金矿是如何运作的?”矿工们去金矿挖金子!”你说。之所以如此是因为你使用的是一个简单的接口,金矿是外部提供,在它内部必须做很多事才能实现。到复杂子系统的这个简单接口是一个外观。
简单来说
Facade模式为复杂的子系统提供了简化的接口。
维基百科说
外观是一个对象,它为更大的代码体(如类库)提供了简化的接口。
程序化示例
以上面的金矿为例。在这里,我们有矿工层次结构

public abstract class DwarvenMineWorker {

  private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class);

  public void goToSleep() {
    LOGGER.info("{} goes to sleep.", name());
  }

  public void wakeUp() {
    LOGGER.info(
"{} wakes up.", name());
  }

  public void goHome() {
    LOGGER.info(
"{} goes home.", name());
  }

  public void goToMine() {
    LOGGER.info(
"{} goes to the mine.", name());
  }

  private void action(Action action) {
    switch (action) {
      case GO_TO_SLEEP:
        goToSleep();
        break;
      case WAKE_UP:
        wakeUp();
        break;
      case GO_HOME:
        goHome();
        break;
      case GO_TO_MINE:
        goToMine();
        break;
      case WORK:
        work();
        break;
      default:
        LOGGER.info(
"Undefined action");
        break;
    }
  }

  public void action(Action... actions) {
    for (Action action : actions) {
      action(action);
    }
  }

  public abstract void work();

  public abstract String name();

  static enum Action {
    GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
  }
}

public class DwarvenTunnelDigger extends DwarvenMineWorker {

  private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class);

  @Override
  public void work() {
    LOGGER.info(
"{} creates another promising tunnel.", name());
  }

  @Override
  public String name() {
    return
"Dwarven tunnel digger";
  }
}

public class DwarvenGoldDigger extends DwarvenMineWorker {

  private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class);

  @Override
  public void work() {
    LOGGER.info(
"{} digs for gold.", name());
  }

  @Override
  public String name() {
    return
"Dwarf gold digger";
  }
}

public class DwarvenCartOperator extends DwarvenMineWorker {

  private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class);

  @Override
  public void work() {
    LOGGER.info(
"{} moves gold chunks out of the mine.", name());
  }

  @Override
  public String name() {
    return
"Dwarf cart operator";
  }
}

为了操作这些金矿工人,我们拥有 facade

public class DwarvenGoldmineFacade {

  private final List<DwarvenMineWorker> workers;

  public DwarvenGoldmineFacade() {
    workers = new ArrayList<>();
    workers.add(new DwarvenGoldDigger());
    workers.add(new DwarvenCartOperator());
    workers.add(new DwarvenTunnelDigger());
  }

  public void startNewDay() {
    makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
  }

  public void digOutGold() {
    makeActions(workers, DwarvenMineWorker.Action.WORK);
  }

  public void endDay() {
    makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
  }

  private static void makeActions(Collection<DwarvenMineWorker> workers,
      DwarvenMineWorker.Action... actions) {
    for (DwarvenMineWorker worker : workers) {
      worker.action(actions);
    }
  }
}

现在使用 facade

DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
facade.startNewDay();
// Dwarf gold digger wakes up.
// Dwarf gold digger goes to the mine.
// Dwarf cart operator wakes up.
// Dwarf cart operator goes to the mine.
// Dwarven tunnel digger wakes up.
// Dwarven tunnel digger goes to the mine.
facade.digOutGold();
// Dwarf gold digger digs for gold.
// Dwarf cart operator moves gold chunks out of the mine.
// Dwarven tunnel digger creates another promising tunnel.
facade.endDay();
// Dwarf gold digger goes home.
// Dwarf gold digger goes to sleep.
// Dwarf cart operator goes home.
// Dwarf cart operator goes to sleep.
// Dwarven tunnel digger goes home.
// Dwarven tunnel digger goes to sleep.

适用场景

  • 您想为复杂的子系统提供简单的接口。子系统随着它们的发展变得越来越复杂。大多数模式在应用时会导致更多更小的类。这使得子系统更易于重复使用并且更易于自定义,但对于不需要自定义它的客户端也变得更难使用。外观模式可以提供子系统的简单默认视图,对大多数客户端来说足够好。只有需要更多可定制性的客户才需要超越外观。
  • 客户端和抽象的实现类之间存在许多依赖关系。引入外观,将子系统与客户端和其他子系统分离,从而提升子系统的独立性和可移植性。
  • 您希望将子系统分层。使用外观来定义每个子系统级别的入口点。如果子系统是相互依赖的,那么您可以通过使它们仅通过它们的外观相互通信来简化它们之间的依赖关系。