責任鏈設計模式

来源:https://www.cnblogs.com/elementplay/archive/2022/07/08/16459910.html
-Advertisement-
Play Games

多維數組 多維數組可以看成是數組的數組,比如二維數組就是一個特殊的一堆數組,其每一個元素都是一個一維數組 二維數組 ​ 首先看一下二維數組的定義: int arr[][]=new int[2][3] 上述定義的數組可以看成是一個2行3列的數組。 我們可以寫代碼來看一下關於二維數組的應用。 代碼示例: ...


在現實生活中,一個事件需要經過 多個對象 處理是很常見的場景。比如:採購審批流程、請假流程等。公司員工請假,可批假的領導有部門負責人、副總經理、總經理等,但每個領導能批准的天數不同,員工必鬚根據需要請求的天數去找不同的領導簽名,即員工必須記住每個領導的姓名、電話和地址信息,這使得該流程變得複雜冗餘。

在電腦軟體開發中也有相關的例子,比如 異常處理,處理程式根據異常的類型決定自己是否處理該異常;還有 Struts2攔截器JSPServlet 的 Filter過濾器等,都可以考慮使用 責任鏈(職責鏈)設計模式 來實現。Servlet 的 Filter過濾器的實現確實使用了 責任鏈設計模式

模式的定義與特點

責任鏈(Chain of Responsibility) 模式的定義:為了避免 請求發送者多個請求處理者 耦合在一起,於是將所有的 請求處理者 通過讓 前一對象 記住 其下一個對象的引用 的方式而形成了一個 鏈條;當有請求發生時,可將請求沿著該 鏈條 傳遞,直到有對象處理當前請求為止。

責任鏈模式 中,客戶只需要將請求發送到 責任鏈 上即可,無需關心請求的 處理 和請求的 傳遞過程,請求會 自動 進行傳遞,因此 責任鏈模式 將請求的 發送者 和請求的 處理者 解耦合了

責任鏈模式是一種 對象行為型 模式

主要優點

  1. 降低了對象之間的 耦合度。該模式使得一個對象無需知道到底是哪一個對象處理其請求,也無需知道 鏈條 的結構,發送者和接收者也無需擁有對方的明確信息
  2. 增強了系統的 可擴展性。可以根據需要增加新的 請求處理類,符合 開閉原則
  3. 增強了給對象指派職責的 靈活性。當工作流程發生變化,可以 動態 的改變 鏈條 內的成員或者調動它們的 次序,也可以 動態 的增加或者刪除責任
  4. 簡化了對象之間的 連接。每個對象只需持有一個指向其後繼者的 引用,不需要持有其它所有處理者的 引用
  5. 責任 分化。每個類只需處理自己該處理的工作,不該處理的傳遞給下一個對象完成,明確各類的 責任範圍,符合 單一職責原則

主要缺點

  1. 不能保證請求一定會被處理。由於請求沒有明確的 接收者,所有不能保證它一定會被處理,該請求可能一直傳遞到 鏈條 的末端都得不到處理
  2. 如果 責任鏈 比較長,請求的處理可能涉及多個處理對象,處理對象過多將會對 系統性能 產生影響
  3. 責任鏈 建立的 合理性 要靠 客戶端 來保證,增加了客戶端的 複雜性,可能會由於 責任鏈 的錯誤設置而導致 系統出錯,如可能造成 迴圈調用(責任鏈的實現基於 遞歸)

模式的結構與實現

模式的結構

  1. 抽象處理者(Handler)角色:定義一個處理請求的 介面 或者 抽象類,包含 抽象處理方法 和一個 後繼連接
  2. 具體處理者(Concrete Handler)角色:實現 抽象處理者處理方法,判斷能否處理本次請求,如果可以處理則處理,否則將請求轉給當前具體處理者的 後繼者
  3. 客戶類(Client)角色:創建處理鏈(即創建 具體處理者 對象),並向 鏈頭 的具體處理者提交請求,它不關心 處理細節 和請求的 傳遞過程

責任鏈模式 的本質是解耦 請求處理,讓請求在 處理鏈 中能進行 傳遞被處理;理解 責任鏈模式 應該理解其 模式,而不是其具體實現。責任鏈模式 的獨到之處是將其節點處理者組合成了 鏈式結構,並允許節點自身決定是否進行 請求處理轉發,相當於讓請求 流動 起來

  • 模式結構圖

責任鏈模式結構圖

  • 責任鏈示意圖

責任鏈示意圖

模式的實現

  1. 抽象處理者角色-Handler
/**
 * 抽象處理者
 */
public abstract class Handler {
    // 定義後繼者引用
    private Handler next;

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }

    // 定義處理請求的抽象方法
    public abstract void handleRequest(String request);
}
  1. 具體處理者角色-ConcreteHandler1ConcreteHandler2
/**
 * 具體處理者1
 */
public class ConcreteHandler1 extends Handler{
    @Override
    public void handleRequest(String request) {
        if("one".equals(request)){ // 具體處理者1能夠處理當前請求
            // 具體處理者1對當前請求進行處理
            System.out.println("具體處理者1負責處理當前請求,已處理完畢...");
        }else { // 具體處理者1不能處理當前請求
            if(this.getNext() != null){ // 當前具體處理者1存在後繼者
                // 將當前請求發送給當前具體處理者1的後繼者
                this.getNext().handleRequest(request);
            }else{ // 當前具體處理者1不存在後繼者
                // 結束請求,返回
                System.out.println("沒有任何處理者處理當前請求,調用結束...");
            }
        }
    }
}
/**
 * 具體處理者2
 */
public class ConcreteHandler2 extends Handler{
    @Override
    public void handleRequest(String request) {
        if("two".equals(request)){ // 具體處理者2能夠處理當前請求
            // 具體處理者2對當前請求進行處理
            System.out.println("具體處理者2負責處理當前請求,已處理完畢...");
        }else { // 具體處理者2不能處理當前請求
            if(this.getNext() != null){ // 當前具體處理者2存在後繼者
                // 將當前請求發送給當前具體處理者2的後繼者
                this.getNext().handleRequest(request);
            }else{ // 當前具體處理者2不存在後繼者
                // 結束請求,返回
                System.out.println("沒有任何處理者處理當前請求,調用結束...");
            }
        }
    }
}
  1. 客戶端角色-Client
/**
 * 客戶端
 */
public class Client {
    public static void main(String[] args) {
        // 創建具體處理者對象,組裝責任鏈
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        // 設置 handler1(第一個具體處理者對象) 的後繼者為 handler2
        handler1.setNext(handler2);
        // 提交請求
        handler1.handleRequest("two");
    }
}
  • 程式運行結果:
具體處理者2負責處理當前請求,已處理完畢...

模式的應用場景

  1. 多個對象 可以處理 同一個請求,但具體由那個對象處理該請求在 運行時 自動確定
  2. 動態 指定一組對象處理請求,或添加新的處理者
  3. 需要在不明確指定請求處理者的情況下,向多個處理者中的一個提交請求

模式的擴展

  • 純的 責任鏈模式:一個請求必須被某一個處理者對象所接收,且一個 具體處理者 對某個請求的處理只能採用 自己處理 或者 交給後繼者處理 兩種方式之一
  • 不純的 責任鏈模式:允許出現某一個 具體處理者 對象在承擔了請求的 一部分責任 之後,又將 剩餘的責任 傳遞給 後繼者,且一個請求可以最終不被任何 接收端對象 所接收(Filter過濾器屬於 不純 的責任鏈模式)

文章轉載於:http://c.biancheng.net/view/1383.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 回想當年剛接觸前端,Ajax 真的碰一次就跪一次。當時不懂後端,不知道 api 是什麼東東,也沒有後端小伙伴寫介面給我測試。 本文整理了我用過的幾個 免費的線上api介面,而且不需要處理跨域等問題。 希望能給剛入門的前端小白在學習 Ajax 時提供一點幫助。 本文列舉的線上介面包括:文本 和 圖片。 ...
  • 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 <meta name="viewp ...
  • @(公眾號測試號H5授權《前端》) Tips:因為申請公眾號需要 ¥300。 so 我用的是測試號。【白嫖永遠不虧】 需要註意的是 測試號是和個人微信號關聯起來的,不是公眾號主體關聯。。也就是每個人都可以申請,而不是必須有公眾號主題才可以。測試號和公眾號是獨立的。 一、前置準備-註冊配置測試賬號 1 ...
  • CSS進階內容 在學習了CSS基本知識之後,我們需要進一步瞭解CSS,因此寫下了這篇文章 當然如果沒有學習之前的知識,可以到我的主頁中查看之前的文章:秋落雨微涼 - 博客園 CSS三大特性 首先我們先來瞭解CSS的三大特點,以便於我們下麵知識點的講解 CSS三大特性包括: 層疊性 繼承性 優先順序 層 ...
  • 經查,發現我們開發的程式是用webpack打包發佈的,而該頁面在微信小程式打開時,對方註入了幾個微信相關的js腳本,而該腳本也是使用webpack打包生成的。雙方的js代碼導致window.webpackJsonp 被重覆定義。 當兩者的webpack版本不同時,生成的 window.webpack ...
  • 隨著Vue3和TypeScript的大浪潮不斷襲來,越來越多的Vue項目採用了TypeScript的語法來編寫代碼,而Vue3的JS中的Setup語法糖也越來越廣泛的使用,給我們這些以前用弱類型的JS語法編寫Vue代碼的人不少衝擊,不過隨著大量的學習和代碼編寫,經歷過一段難熬的時間後,逐步適應了這種... ...
  • 從屏幕上下左右滑入滑出效果,代碼比較粗糙,但是效果已實現 需要註意的是,從屏幕右邊和下邊滑入的時候,需要給滑動的容器外面再加一個容器,加樣式 position: fixed; 讓它 固定定位,否則頁面右邊和底部會出現滾動條 主要使用了 css animate 屬性 <!DOCTYPE html> < ...
  • 從排查一次匪夷所思的coredump,引出各種體系架構的差異。 本文中的所有內容來自學習DCC888的學習筆記或者自己理解的整理,如需轉載請註明出處。周榮華@燧原科技 1 背景 從全世界有記載的第一臺電腦Z1 (computer) - Wikipedia在1936年發明,到1946年馮諾依曼體系架 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...