每天一個設計模式之責任鏈模式
- 2020 年 1 月 3 日
- 筆記
作者按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前採用
javascript
和python
兩種語言實現。誠然,每種設計模式都有多種實現方式,但此小冊只記錄最直截了當的實現方式 🙂
0. 項目地址
1. 什麼是「責任鏈模式」?
責任鏈模式:多個對象均有機會處理請求,從而解除發送者和接受者之間的耦合關係。這些對象連接成為鏈式結構,每個節點轉發請求,直到有對象處理請求為止。
其核心就是:請求者不必知道是誰哪個節點對象處理的請求。如果當前不符合終止條件,那麼把請求轉發給下一個節點處理。
而當需求具有「傳遞」的性質時(程式碼中其中一種體現就是:多個if、else if、else if、else
嵌套),就可以考慮將每個分支拆分成一個節點對象,拼接成為責任鏈。
2. 優點與代價
- 優點
- 可以根據需求變動,任意向責任鏈中添加 / 刪除節點對象
- 沒有固定的「開始節點」,可以從任意節點開始
- 代價:責任鏈最大的代價就是每個節點帶來的多餘消耗。當責任鏈過長,很多節點只有傳遞的作用,而不是真正地處理邏輯。
3. 程式碼實現
為了方便演示,模擬常見的「日誌列印」場景。模擬了 3 種級別的日誌輸出:
-
LogHandler
: 普通日誌 -
WarnHandler
:警告日誌 -
ErrorHandler
:錯誤日誌
首先我們會構造「責任鏈」:LogHandler
-> WarnHandler
-> ErrorHandler
。LogHandler
作為鏈的開始節點。
如果是普通日誌,那麼就由 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. 參考
- 《JavaScript 設計模式和開發實踐》
- javascript 之 責任鏈模式
- 職責鏈模式
5. ? 部落格軟廣 ?
個人技術部落格-godbmw.com 歡迎來玩! 每周至少 1 篇原創技術分享,還有開源教程(webpack、設計模式)、面試刷題(偏前端)、知識整理(每周零碎),歡迎長期關注!本篇部落格地址是:《每天一個設計模式之責任鏈模式》。
如果您也想嘗試知識整理 + 搭建功能完善/設計簡約/快速啟動的個人部落格,請直接戳theme-bmw