每天一個設計模式之責任鏈模式

作者按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前採用javascriptpython兩種語言實現。誠然,每種設計模式都有多種實現方式,但此小冊只記錄最直截了當的實現方式 🙂

0. 項目地址

1. 什麼是「責任鏈模式」?

責任鏈模式:多個對象均有機會處理請求,從而解除發送者和接受者之間的耦合關係。這些對象連接成為鏈式結構,每個節點轉發請求,直到有對象處理請求為止。

其核心就是:請求者不必知道是誰哪個節點對象處理的請求。如果當前不符合終止條件,那麼把請求轉發給下一個節點處理。

而當需求具有「傳遞」的性質時(程式碼中其中一種體現就是:多個if、else if、else if、else嵌套),就可以考慮將每個分支拆分成一個節點對象,拼接成為責任鏈。

2. 優點與代價

  • 優點
    • 可以根據需求變動,任意向責任鏈中添加 / 刪除節點對象
    • 沒有固定的「開始節點」,可以從任意節點開始
  • 代價:責任鏈最大的代價就是每個節點帶來的多餘消耗。當責任鏈過長,很多節點只有傳遞的作用,而不是真正地處理邏輯。

3. 程式碼實現

為了方便演示,模擬常見的「日誌列印」場景。模擬了 3 種級別的日誌輸出:

  • LogHandler: 普通日誌
  • WarnHandler:警告日誌
  • ErrorHandler:錯誤日誌

首先我們會構造「責任鏈」:LogHandler -> WarnHandler -> ErrorHandlerLogHandler作為鏈的開始節點。

如果是普通日誌,那麼就由 LogHandler 處理,停止傳播;如果是 Warn 級別的日誌,那麼 LogHandler 就會自動向下傳遞,WarnHandler 接收到並且處理,停止傳播;Error 級別日誌同理。

3.1 ES6 實現

class Handler {    constructor() {      this.next = null;    }      setNext(handler) {      this.next = handler;    }  }    class LogHandler extends Handler {    constructor(...props) {      super(...props);      this.name = "log";    }      handle(level, msg) {      if (level === this.name) {        console.log(`LOG: ${msg}`);        return;      }      this.next && this.next.handle(...arguments);    }  }    class WarnHandler extends Handler {    constructor(...props) {      super(...props);      this.name = "warn";    }      handle(level, msg) {      if (level === this.name) {        console.log(`WARN: ${msg}`);        return;      }      this.next && this.next.handle(...arguments);    }  }    class ErrorHandler extends Handler {    constructor(...props) {      super(...props);      this.name = "error";    }      handle(level, msg) {      if (level === this.name) {        console.log(`ERROR: ${msg}`);        return;      }      this.next && this.next.handle(...arguments);    }  }    /******************以下是測試程式碼******************/    let logHandler = new LogHandler();  let warnHandler = new WarnHandler();  let errorHandler = new ErrorHandler();    // 設置下一個處理的節點  logHandler.setNext(warnHandler);  warnHandler.setNext(errorHandler);    logHandler.handle("error", "Some error occur");

3.2 Python3 實現

class Handler():      def __init__(self):          self.next = None        def set_next(self, handler):          self.next = handler      class LogHandler(Handler):      def __init__(self):          super().__init__()          self.__name = "log"        def handle(self, level, msg):          if level == self.__name:              print('LOG: ', msg)              return            if self.next != None:              self.next.handle(level, msg)      class WarnHandler(Handler):      def __init__(self):          super().__init__()          self.__name = "warn"        def handle(self, level, msg):          if level == self.__name:              print('WARN: ', msg)              return            if self.next != None:              self.next.handle(level, msg)      class ErrorHandler(Handler):      def __init__(self):          super().__init__()          self.__name = "error"        def handle(self, level, msg):          if level == self.__name:              print('ERROR: ', msg)              return            if self.next != None:              self.next.handle(level, msg)      # 以下是測試程式碼  log_handler = LogHandler()  warn_handler = WarnHandler()  error_handler = ErrorHandler()    # 設置下一個處理的節點  log_handler.set_next(warn_handler)  warn_handler.set_next(error_handler)    log_handler.handle("error", "Some error occur")

4. 參考

5. ? 部落格軟廣 ?

個人技術部落格-godbmw.com 歡迎來玩! 每周至少 1 篇原創技術分享,還有開源教程(webpack、設計模式)、面試刷題(偏前端)、知識整理(每周零碎),歡迎長期關注!本篇部落格地址是:《每天一個設計模式之責任鏈模式》

如果您也想嘗試知識整理 + 搭建功能完善/設計簡約/快速啟動的個人部落格,請直接戳theme-bmw