設(shè)計(jì)模式 - 外觀模式 facade

介紹

  • 1、使用頻率高,常見的是第三方庫。
  • 2、對外可見的只有一兩個類,而內(nèi)部涉及可能是個很龐大很復(fù)雜的系統(tǒng)。

定義

  • 1、 要求子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個統(tǒng)一的對象進(jìn)行。
  • 2、 提供一個高層次的接口,使得子系統(tǒng)更易于使用。

使用場景

  • 1、某個模塊很龐大或很復(fù)雜,希望外部能很簡單就使用。
  • 2、希望能把控入口,外部只能通過某個類來訪問,這樣以后要換方案就不會影響外部使用。

簡單點(diǎn):一個模塊很復(fù)雜,但我們使用只需要一個類簡單操作就可以了。


形象的例子.png

再來舉個例子吧


舉個例子

A:金礦是怎么挖出來的?
B:礦工到礦井里就挖出來的唄
在外部只知道這些,但其實(shí)涉及到很多功能模塊,這就是「外觀模式」,讓別人以為就是這么簡單。

先看下涉及到的一些名詞:

    1. Dwarven 矮人(霍比特中就是矮人來挖金礦的) DwarvenMineWorker 矮人曠工
    1. DwarvenTunnelDigger 挖隧道矮人
    1. DwarvenGoldDigger 挖金礦矮人
    1. DwarvenCartOperator 運(yùn)輸?shù)陌?/li>

我比較傾向于逆向看代碼,也就是先看到結(jié)果,在順藤摸瓜。那就先上結(jié)果:

public class App {
  public static void main(String[] args) {
    DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
    facade.startNewDay();
    facade.digOutGold();
    facade.endDay();
  }
}

很簡單,就是 new 一個 facade 出來,調(diào)用相應(yīng)的方法,「開始新的一天」-->「挖礦」-->「結(jié)束」,結(jié)果:

DwarvenMineWorker - Dwarf gold digger wakes up.
DwarvenMineWorker - Dwarf gold digger goes to the mine.
DwarvenMineWorker - Dwarf cart operator wakes up.
DwarvenMineWorker - Dwarf cart operator goes to the mine.
DwarvenMineWorker - Dwarven tunnel digger wakes up.
DwarvenMineWorker - Dwarven tunnel digger goes to the mine.
DwarvenGoldDigger - Dwarf gold digger digs for gold.
DwarvenCartOperator - Dwarf cart operator moves gold chunks out of the mine.
DwarvenTunnelDigger - Dwarven tunnel digger creates another promising tunnel.
DwarvenMineWorker - Dwarf gold digger goes home.
DwarvenMineWorker - Dwarf gold digger goes to sleep.
DwarvenMineWorker - Dwarf cart operator goes home.
DwarvenMineWorker - Dwarf cart operator goes to sleep.
DwarvenMineWorker - Dwarven tunnel digger goes home.
DwarvenMineWorker - Dwarven tunnel digger goes to sleep.

看到這個過程由三個類型參與的,順藤摸瓜,我們先看下 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);
    }
  }
}

簡單說明下,在構(gòu)造中添加了三個類型的工作者,在每個動作中都會調(diào)用工作者的具體操作。

接著我們拿一個曠工矮人來看下具體實(shí)現(xiàn):

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";
  }
}

可以看到只是實(shí)現(xiàn)了父類定義的抽象方法(顯示名稱、工作內(nèi)容),那么接著看下父類的實(shí)現(xiàn):

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;
    }
  }

  // 執(zhí)行任務(wù)
  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
  }
}

這個父類中提供了:醒來、去礦井、工作、回家、睡覺的操作.

在回頭看下最開始,我們只是 DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();然后就調(diào)用一些操作 facade.startNewDay() ,就讓整個礦場工作起來了。
對于外部, 可見的只是 DwarvenGoldmineFacade ,但內(nèi)部可能是很復(fù)雜的操作。

還有另一個使用場景:整個功能模塊用的 SDK 可能過不久換另一個 SDK 來實(shí)現(xiàn)。這時候我們也可以考慮使用「外觀模式」來控制外界訪問。更換時就不會影響到具體使用。

我們做開發(fā)時,一定要先做好需求分析,反復(fù)確認(rèn)需求之后,選擇適當(dāng)?shù)目蚣?。在使用別人的庫時,可以先自己封裝一回,使用自己封裝的類而不是直接使用別人的庫。這樣做得好處就是更換庫不至于全盤都要修改。

當(dāng)我們自己寫個復(fù)雜的功能或系統(tǒng)供外部(也可以是自己)使用時,也可以考慮使用外觀模式,讓外部使用更簡單,還能控制好出口。

參考:

  1. java-design-patterns
  2. Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容