責任鏈設計模式

来源: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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...