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

godbmw發表於2019-01-07

作者按:《每天一個設計模式》旨在初步領會設計模式的精髓,目前採用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

相關文章