24種設計模式之行為模式(一)- 職責鏈模式

實戰案例: ** 采購單的分級審批**

Sunny軟件公司程節了一個采購審批子系統,其采購審批是分級進行的,根據不同的采購金額由不同層次的主管進行審批。主任審批5萬一下,副董事長審批5萬到10萬。董事長審批10萬-50萬的采購單。其流程如圖所示:

采購流程

在實現分級審批的時候,小明開發元提出了一個初始解決方案,使用PurchaseRequestHandler統一處理采購單,框架代碼如下:

Class PurchaseRequestHandler{
  public void sendRequestToDirectror(PurchaseRequest request){
    if(request.getAmount()<50000)
      //主管審批
      this.handlerByDirector(request);
    else if(request.getAmount()<100000)
      //副董事長審批采購
      this.handlerByVicePresident(request);
......//省略一大堆
  }
}

通過上述代碼,我們分析一下,會有這幾個問題:

  1. 如果審批流程更長,會導致該類代碼越來越多,且各個級別的審批都在一個類中,違反了單一職責原則 ,測試維護難度大。

  2. 修改審批細節都必須對源代碼進行修改并測試,違反了開閉原則。

  3. 審批流程缺乏靈活性,只能通過改源代碼實現流程的修改,無法動態調整。
    上述問題想要解決,我們可以使用職責鏈模式,下面就讓我們打開新世界的大門吧。

職責鏈概述

職責鏈模式可以將請求的處理者組織成一條鏈,并讓請求沿著鏈傳遞,由鏈上的處理著對請求進行處理,客戶端無需關心請求的處理細節以及請求的傳遞,只需將請求發送到鏈上即可,實現請求發送者和請求處理者的解耦。

定義:職責鏈模式(Chain of Responsibility Pattern):避免請求發送者與接受者耦合在一起,讓多個對象都有可能接收請求,將這些對象連接成一條鏈,并且沿著這條鏈傳遞請求,知道有對象處理它為止。職責鏈模式是一種對象行為模式。

職責鏈模式結構的核心在于引入了抽象處理者:如圖:

職責鏈模式結構圖

職責鏈模式結構圖中包含如下幾個角色:

  • Handler: 定義了處理請求的接口,一般設計為抽象類,由具體不同的具體處理著處理請求的方式不同,因此定義抽象請求處理方法。因為每個處理者的下家還是一個處理者,因此在抽象處理者定義了一個抽象處理者類型的對象,作為下家引用。通過該引用,處理著可以連成一條鏈。
  • ConcreteHandler(具體處理者):他是抽象處理者的子類,可以處理用戶請求,在具體處理者類中實現了抽象處理者定義的抽象請求處理方法,在處理請求之前進行判斷,看是否有相應的處理權限,如果可以處理請求就處理它,否則轉發給后者;在具體處理者中可以訪問鏈中下一個對象,一遍請求的轉發。
    在職責鏈中:很多對象由每一個對象對其下家的引用而鏈接起來形成一條鏈。請求在這個鏈上傳遞,知道鏈上某個對象決定處理刺請求。發出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織鏈和分配責任。

純與不純的職責鏈模式

  1. 純的職責鏈模式:
    一個純的職責鏈模式要求一個具體處理者對象只能在兩個行為中選擇一個:要么承擔全部責 任,要么將責任推給下家,不允許出現某一個具體處理者對象在承擔了一部分或全部責任后 又將責任向下傳遞的情況。而且在純的職責鏈模式中,要求一個請求必須被某一個處理者對 象所接收,不能出現某個請求未被任何一個處理者對象處理的情況。在前面的采購單審批實 例中應用的是純的職責鏈模式。
  2. 不純的職責鏈模式:
    在一個不純的職責鏈模式中允許某個請求被一個具體處理者部分處理后再向下傳遞,或者一 個具體處理者處理完某請求后其后繼處理者可以繼續處理該請求,而且一個請求可以最終不 被任何處理者對象所接收。Java AWT 1.0中的事件處理模型應用的是不純的職責鏈模式,其基 本原理如下:由于窗口組件(如按鈕、文本框等)一般都位于容器組件中,因此當事件發生 在某一個組件上時,先通過組件對象的handleEvent()方法將事件傳遞給相應的事件處理方法, 該事件處理方法將處理此事件,然后決定是否將該事件向上一級容器組件傳播;上級容器組 件在接到事件之后可以繼續處理此事件并決定是否繼續向上級容器組件傳播,如此反復,直 到事件到達頂層容器組件為止;如果一直傳到最頂層容器仍沒有處理方法,則該事件不予處 理。每一級組件在接收到事件時,都可以處理此事件,而不論此事件是否在上一級已得到處 理,還存在事件未被處理的情況。顯然,這就是不純的職責鏈模式,早期的Java AWT事件模 型(JDK 1.0及更早)中的這種事件處理機制又叫事件浮升(Event Bubbling)機制。從Java.1.1以 后,JDK使用觀察者模式代替職責鏈模式來處理事件。目前,在JavaScript中仍然可以使用這 種事件浮升機制來進行事件處理。

職責鏈模式總結

職責鏈模式通過建立一條鏈來組織請求的處理者,請求將沿著鏈進行傳遞,請求發送者無須 知道請求在何時、何處以及如何被處理,實現了請求發送者與處理者的解耦。在軟件開發 中,如果遇到有多個對象可以處理同一請求時可以應用職責鏈模式,例如在Web應用開發中創 建一個過濾器(Filter)鏈來對請求數據進行過濾,在工作流系統中實現公文的分級審批等等,使 用職責鏈模式可以較好地解決此類問題。

職責鏈模式優缺點

優點:

  • 職責鏈模式使得一個對象無須知道是其他哪一個對象處理其請求,對象僅需知道該請求會 被處理即可,接收者和發送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結構, 由客戶端負責鏈的創建,降低了系統的耦合度。
  • 請求處理對象僅需維持一個指向其后繼者的引用,而不需要維持它對所有的候選處理者的 引用,可簡化對象的相互連接。
  • 在給對象分派職責時,職責鏈可以給我們更多的靈活性,可以通過在運行時對該鏈進行動 態的增加或修改來增加或改變處理一個請求的職責。
  • 在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,只需要在客戶端重新 建鏈即可,從這一點來看是符合“開閉原則”的。

缺點:

  • 由于一個請求沒有明確的接收者,那么就不能保證它一定會被處理,該請求可能一直到鏈 的末端都得不到處理;一個請求也可能因職責鏈沒有被正確配置而得不到處理。
  • 對于比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統性能將受到一定影響, 而且在進行代碼調試時不太方便。
  • 如果建鏈不當,可能會造成循環調用,將導致系統陷入死循環。

適用場景

  • 有多個對象可以處理同一個請求,具體哪個對象處理該請求待運行時刻再確定,客戶端只 需將請求提交到鏈上,而無須關心請求的處理對象是誰以及它是如何處理的。
  • 在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
  • 可動態指定一組對象處理請求,客戶端可以動態創建職責鏈來處理請求,還可以改變鏈中 處理者之間的先后次序。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,577評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,486評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,852評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,600評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,944評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,108評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,652評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,385評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,616評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,798評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,205評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,537評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,334評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,570評論 2 379

推薦閱讀更多精彩內容