責任鏈模式:優雅處理復雜流程的設計藝術

引言

在軟件設計中,我們經常會遇到需要按特定順序處理請求的場景。例如,一個訂單處理系統可能需要經過驗證、付款、物流安排和客戶通知等多個步驟。如果我們將這些步驟硬編碼在一個方法中,代碼將變得臃腫且難以維護。這時,責任鏈模式(Chain of Responsibility Pattern)就顯示出了它的價值。

責任鏈模式是一種行為設計模式,它允許多個對象依次處理同一個請求,從而將請求的發送者與接收者解耦。本文將詳細介紹責任鏈模式的核心概念、實現方法以及適用場景。

什么是責任鏈模式?

責任鏈模式是這樣工作的:一個請求沿著一條預定義的對象鏈傳遞,直到有一個對象處理它或者請求到達鏈尾。每個處理者決定是自己處理請求還是將其傳遞給鏈中的下一個對象。

這種模式的美妙之處在于:請求的發送者不需要知道誰會處理這個請求,而每個處理者也只需要關注自己的職責,無需知道整個鏈的結構。

責任鏈模式的核心組件

  1. 抽象處理者(Handler): 定義了處理請求的接口,通常包含設置下一個處理者和處理請求的方法。
  2. 具體處理者(ConcreteHandler): 實現抽象處理者的接口,處理自己負責的請求,如果不能處理則傳遞給下一個處理者。
  3. 客戶端(Client): 創建處理者對象并組成責任鏈,然后向鏈上的第一個處理者發送請求。

類圖

下面是責任鏈模式的類圖:

責任鏈模式的實現

讓我們以一個訂單處理系統為例,說明如何實現責任鏈模式:

1. 創建訂單類

/*** 訂單類 - 包含訂單的基本信息和處理狀態*/
public class Order {private int id;                  // 訂單IDprivate double amount;           // 訂單金額private String customerName;     // 客戶名稱private boolean isValidated;     // 訂單是否已驗證private boolean isPaymentProcessed; // 支付是否已處理private boolean isDeliveryArranged; // 配送是否已安排private boolean isNotificationSent;  // 通知是否已發送/*** 訂單構造函數* @param id 訂單ID* @param amount 訂單金額* @param customerName 客戶名稱*/public Order(int id, double amount, String customerName) {this.id = id;this.amount = amount;this.customerName = customerName;this.isValidated = false;this.isPaymentProcessed = false;this.isDeliveryArranged = false;this.isNotificationSent = false;}// Getters and setterspublic int getId() {return id;}public double getAmount() {return amount;}public String getCustomerName() {return customerName;}public boolean isValidated() {return isValidated;}public void setValidated(boolean validated) {isValidated = validated;}public boolean isPaymentProcessed() {return isPaymentProcessed;}public void setPaymentProcessed(boolean paymentProcessed) {this.isPaymentProcessed = paymentProcessed;}public boolean isDeliveryArranged() {return isDeliveryArranged;}public void setDeliveryArranged(boolean deliveryArranged) {this.isDeliveryArranged = deliveryArranged;}public boolean isNotificationSent() {return isNotificationSent;}public void setNotificationSent(boolean notificationSent) {this.isNotificationSent = notificationSent;}@Overridepublic String toString() {return "Order{" +"id=" + id +", amount=" + amount +", customerName='" + customerName + '\'' +", isValidated=" + isValidated +", isPaymentProcessed=" + isPaymentProcessed +", isDeliveryArranged=" + isDeliveryArranged +", isNotificationSent=" + isNotificationSent +'}';}
}

2. 創建處理器接口

/*** 訂單處理器抽象類 - 責任鏈模式的核心* 定義了處理訂單的通用接口和設置下一個處理器的方法*/
public abstract class OrderHandler {protected OrderHandler nextHandler; // 責任鏈中的下一個處理器/*** 設置責任鏈中的下一個處理器* @param nextHandler 下一個處理器*/public void setNextHandler(OrderHandler nextHandler) {this.nextHandler = nextHandler;}/*** 處理訂單的抽象方法,由具體的處理器實現* @param order 要處理的訂單*/public abstract void handleOrder(Order order);
}

3. 實現具體的處理器類

訂單驗證處理器
/*** 訂單驗證處理器 - 責任鏈的第一環* 負責驗證訂單的基本信息是否有效*/
public class OrderValidationHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {System.out.println("OrderValidationHandler: 驗證訂單 #" + order.getId());// 驗證訂單邏輯if (order.getAmount() <= 0) {System.out.println("OrderValidationHandler: 訂單金額無效,處理終止");return; // 終止責任鏈,不再繼續處理}if (order.getCustomerName() == null || order.getCustomerName().isEmpty()) {System.out.println("OrderValidationHandler: 客戶信息無效,處理終止");return; // 終止責任鏈,不再繼續處理}// 標記為已驗證order.setValidated(true);System.out.println("OrderValidationHandler: 訂單 #" + order.getId() + " 已驗證通過");// 傳遞給下一個處理器if (nextHandler != null) {nextHandler.handleOrder(order); // 繼續責任鏈的處理流程}}
}
支付處理器
/*** 支付處理器 - 責任鏈的第二環* 負責處理訂單的支付流程*/
public class PaymentProcessHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 檢查訂單是否已驗證,確保責任鏈的順序性if (!order.isValidated()) {System.out.println("PaymentProcessHandler: 訂單 #" + order.getId() + " 未通過驗證,無法處理支付");return; // 前置條件不滿足,終止處理}System.out.println("PaymentProcessHandler: 處理訂單 #" + order.getId() + " 的支付,金額: " + order.getAmount());// 模擬支付處理邏輯// 這里可以加入支付網關調用等實際業務邏輯boolean paymentSuccessful = processPayment(order);if (paymentSuccessful) {order.setPaymentProcessed(true);System.out.println("PaymentProcessHandler: 訂單 #" + order.getId() + " 支付成功");// 傳遞給下一個處理器if (nextHandler != null) {nextHandler.handleOrder(order); // 繼續責任鏈的處理流程}} else {System.out.println("PaymentProcessHandler: 訂單 #" + order.getId() + " 支付失敗,處理終止");// 支付失敗,終止責任鏈}}/*** 處理支付的內部方法* @param order 要處理支付的訂單* @return 支付是否成功*/private boolean processPayment(Order order) {// 模擬支付處理// 在實際應用中,這里會調用支付網關APIreturn order.getAmount() <= 10000; // 假設10000以上的訂單需要額外審核}
}
配送安排處理器
/*** 配送安排處理器 - 責任鏈的第三環* 負責為已支付的訂單安排配送*/
public class DeliveryArrangementHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 檢查訂單是否已支付,確保責任鏈的順序性if (!order.isPaymentProcessed()) {System.out.println("DeliveryArrangementHandler: 訂單 #" + order.getId() + " 未完成支付,無法安排配送");return; // 前置條件不滿足,終止處理}System.out.println("DeliveryArrangementHandler: 為訂單 #" + order.getId() + " 安排配送");// 模擬配送安排邏輯arrangeDelivery(order);order.setDeliveryArranged(true);System.out.println("DeliveryArrangementHandler: 訂單 #" + order.getId() + " 已安排配送");// 傳遞給下一個處理器if (nextHandler != null) {nextHandler.handleOrder(order); // 繼續責任鏈的處理流程}}/*** 安排配送的內部方法* @param order 要安排配送的訂單*/private void arrangeDelivery(Order order) {// 模擬配送安排// 在實際應用中,這里會與物流系統對接System.out.println("DeliveryArrangementHandler: 正在為客戶 " + order.getCustomerName() + " 安排遞送服務");}
}
通知處理器
/*** 通知處理器 - 責任鏈的最后一環* 負責在訂單處理完成后發送通知給客戶*/
public class NotificationHandler extends OrderHandler {@Overridepublic void handleOrder(Order order) {// 檢查訂單是否已安排配送,確保責任鏈的順序性if (!order.isDeliveryArranged()) {System.out.println("NotificationHandler: 訂單 #" + order.getId() + " 未安排配送,無法發送通知");return; // 前置條件不滿足,終止處理}System.out.println("NotificationHandler: 發送訂單 #" + order.getId() + " 的通知");// 模擬發送通知邏輯sendNotification(order);order.setNotificationSent(true);System.out.println("NotificationHandler: 訂單 #" + order.getId() + " 的通知已發送");// 完成處理,這是責任鏈的最后一環System.out.println("訂單 #" + order.getId() + " 處理完成!");}/*** 發送通知的內部方法* @param order 要發送通知的訂單*/private void sendNotification(Order order) {// 模擬發送通知// 在實際應用中,這里會調用郵件或短信服務System.out.println("NotificationHandler: 向客戶 " + order.getCustomerName() + " 發送訂單確認通知");}
}

4. 創建客戶端測試類

/*** 訂單處理器 - 客戶端類* 負責構建和初始化責任鏈,并啟動訂單處理流程*/
public class OrderProcessor {private OrderHandler chain; // 責任鏈的起點/*** 構造函數,初始化責任鏈*/public OrderProcessor() {// 構建責任鏈buildOrderProcessingChain();}/*** 構建訂單處理責任鏈* 設定處理器的順序:驗證 -> 支付 -> 配送 -> 通知*/private void buildOrderProcessingChain() {// 創建各個處理器OrderHandler validationHandler = new OrderValidationHandler();OrderHandler paymentHandler = new PaymentProcessHandler();OrderHandler deliveryHandler = new DeliveryArrangementHandler();OrderHandler notificationHandler = new NotificationHandler();// 設置處理器鏈,定義處理順序validationHandler.setNextHandler(paymentHandler);paymentHandler.setNextHandler(deliveryHandler);deliveryHandler.setNextHandler(notificationHandler);// 設置責任鏈的起點this.chain = validationHandler;}/*** 處理訂單的方法,將訂單傳入責任鏈的起點* @param order 要處理的訂單*/public void processOrder(Order order) {System.out.println("開始處理訂單 #" + order.getId());chain.handleOrder(order); // 啟動責任鏈處理}
}

5. 主類用于運行示例

/*** 責任鏈模式演示類* 用于測試責任鏈在不同訂單場景下的行為*/
public class ChainOfResponsibilityDemo {public static void main(String[] args) {// 創建訂單處理器OrderProcessor processor = new OrderProcessor();// 測試案例1: 有效訂單 - 應該完成所有處理步驟Order validOrder = new Order(1001, 1200.50, "張三");System.out.println("=== 處理有效訂單 ===");processor.processOrder(validOrder);System.out.println("最終訂單狀態: " + validOrder);System.out.println();// 測試案例2: 金額無效的訂單 - 應在驗證階段終止Order invalidAmountOrder = new Order(1002, 0, "李四");System.out.println("=== 處理金額無效的訂單 ===");processor.processOrder(invalidAmountOrder);System.out.println("最終訂單狀態: " + invalidAmountOrder);System.out.println();// 測試案例3: 客戶信息為空的訂單 - 應在驗證階段終止Order noCustomerOrder = new Order(1003, 2500.75, "");System.out.println("=== 處理客戶信息為空的訂單 ===");processor.processOrder(noCustomerOrder);System.out.println("最終訂單狀態: " + noCustomerOrder);System.out.println();}
}

6. 測試結果

責任鏈模式的優點

  1. 降低耦合度: 發送者與接收者解耦,發送者不需要知道誰會處理請求。
  2. 增加靈活性: 可以動態地改變責任鏈的成員或者調整處理順序。
  3. 單一職責: 每個處理者只關注自己的職責,符合單一職責原則。
  4. 開閉原則: 可以在不修改現有代碼的情況下增加新的處理者,符合開閉原則。

責任鏈模式的缺點

  1. 性能考量: 請求可能需要經過多個處理者才能得到處理,增加了處理時間。
  2. 保證處理: 如果責任鏈設計不當,可能導致請求無法被處理。
  3. 調試困難: 請求的流向可能不明確,增加了調試難度。

責任鏈模式的應用場景

責任鏈模式適用于以下場景:

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

實際應用例子:

  • Web應用中的過濾器和攔截器
  • 日志記錄系統的級別處理
  • 異常處理機制
  • 工作流系統中的審批流程

總結

責任鏈模式通過將請求沿著處理者鏈進行傳遞,實現了請求發送者與接收者之間的解耦。它不僅使代碼更加整潔和模塊化,還提高了系統的靈活性和可維護性。在處理復雜流程和事件傳遞時,責任鏈模式是一個非常有價值的設計工具。

當你的系統中出現一系列處理者,它們以特定順序處理請求,且請求的處理流程靈活多變時,請考慮使用責任鏈模式。它將幫助你構建更加優雅和可擴展的系統架構。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72755.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72755.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72755.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【STM32】玩轉IIC之驅動MPU6050及姿態解算

目錄 前言 一.MPU6050模塊介紹 1.1MPU6050簡介 1.2 MPU6050的引腳定義 1.3MPU6050寄存器解析 二.MPU6050驅動開發 2.1 配置寄存器 2.2對MPU6050寄存器進行讀寫 2.2.1 寫入寄存器 2.2.2讀取寄存器 2.3 初始化MPU6050 2.3.1 設置工作模式 2.3.2 配置采樣率 2.3.3 啟…

【ThreeJS Basics 09】Debug

文章目錄 簡介從 dat.GUI 到 lil-gui例子安裝 lil-gui 并實例化不同類型的調整改變位置針對非屬性的調整復選框顏色 功能/按鈕調整幾何形狀文件夾調整 GUI寬度標題關閉文件夾隱藏按鍵切換 結論 簡介 每一個創意項目的一個基本方面是能夠輕松調整。開發人員和參與項目的其他參與…

【Pandas】pandas Series explode

Pandas2.2 Series Computations descriptive stats 方法描述Series.argsort([axis, kind, order, stable])用于返回 Series 中元素排序后的索引位置的方法Series.argmin([axis, skipna])用于返回 Series 中最小值索引位置的方法Series.argmax([axis, skipna])用于返回 Series…

電腦網絡出現問題!簡單的幾種方法解除電腦飛行模式

在某些情況下&#xff0c;您可能需要關閉電腦上的飛行模式以便重新連接到 Wi-Fi、藍牙或其他無線網絡。本教程中簡鹿辦公將指導您如何在 Windows 和 macO S操作系統上解除飛行模式。 一、Windows 系統下解除飛行模式 通過快捷操作中心 步驟一&#xff1a;點擊屏幕右下角的通知…

nature genetics | SCENT:單細胞多模態數據揭示組織特異性增強子基因圖譜,并可識別致病等位基因

–https://doi.org/10.1038/s41588-024-01682-1 Tissue-specific enhancer–gene maps from multimodal single-cell data identify causal disease alleles 研究團隊和單位 Alkes L. Price–Broad Institute of MIT and Harvard Soumya Raychaudhuri–Harvard Medical S…

MyBatis-Plus 與 Spring Boot 的最佳實踐

在現代 Java 開發中,MyBatis-Plus 和 Spring Boot 的結合已經成為了一種非常流行的技術棧。MyBatis-Plus 是 MyBatis 的增強工具,提供了許多便捷的功能,而 Spring Boot 則簡化了 Spring 應用的開發流程。本文將探討如何將 MyBatis-Plus 與 Spring Boot 進行整合,并分享一些…

uploadlabs通關思路

目錄 靶場準備 復現 pass-01 代碼審計 執行邏輯 文件上傳 方法一&#xff1a;直接修改或刪除js腳本 方法二&#xff1a;修改文件后綴 pass-02 代碼審計 文件上傳 1. 思路 2. 實操 pass-03 代碼審計 過程&#xff1a; 文件上傳 pass-04 代碼審計 文件上傳 p…

AI編程工具節選

1、文心快碼 百度基于文心大模型推出的一款智能編碼助手&#xff0c; 官網地址&#xff1a;文心快碼(Baidu Comate)更懂你的智能代碼助手 2、通義靈碼 阿里云出品的一款基于通義大模型的智能編碼輔助工具&#xff0c; 官網地址&#xff1a;通義靈碼_你的智能編碼助手-阿里云 …

目錄掃描工具深度對比:Dirb、Dirsearch、DirBuster、Feroxbuster 與 Gobuster

? 前言 在網絡安全測試與滲透測試中&#xff0c;目錄掃描&#xff08;又稱目錄枚舉&#xff09;是一項至關重要的技術。它用于發現 Web 服務器上未公開的隱藏目錄和文件&#xff0c;這些資源可能包含敏感數據、配置文件甚至潛在漏洞&#xff0c;因而成為攻擊者與安全研究人員…

“雙碳”背景下,企業應該如何提升能源效率?

在當今競爭激烈的市場環境中&#xff0c;企業不僅需要優化成本&#xff0c;還需積極響應國家的能源政策&#xff0c;減少對環境的影響。提升工業能源效率正是實現這一雙重目標的關鍵。中國近年來大力推進“雙碳”目標&#xff08;碳達峰、碳中和&#xff09;&#xff0c;并出臺…

無人機擴頻技術對比!

一、技術原理與核心差異 FHSS&#xff08;跳頻擴頻&#xff09; 核心原理&#xff1a;通過偽隨機序列控制載波頻率在多個頻點上快速跳變&#xff0c;收發雙方需同步跳頻序列。信號在某一時刻僅占用窄帶頻譜&#xff0c;但整體覆蓋寬頻帶。 技術特點&#xff1a; 抗干擾…

當AI開始“思考“:拆解大模型訓練與推理的秘密(以DeepSeek為例)

如果你用過deepseek&#xff0c;可能體驗過它在幾秒內編故事、寫代碼的震撼。但你是否想過&#xff0c;這種"智能輸出"背后存在兩種完全不同的底層機制&#xff1f;就像人類需要先學習知識&#xff08;訓練&#xff09;才能考試答題&#xff08;推理&#xff09;&…

永洪科技深度分析實戰,零售企業的銷量預測

隨著人工智能技術的不斷發展&#xff0c;智能預測已經成為各個領域的重要應用之一。現在&#xff0c;智能預測技術已經廣泛應用于金融、零售、醫療、能源等領域&#xff0c;為企業和個人提供決策支持。 智能預測技術通過分析大量的數據&#xff0c;利用機器學習和深度學習算法…

Vue項目通過內嵌iframe訪問另一個vue頁面,獲取token適配后端鑒權(以內嵌若依項目舉例)

1. 改造子Vue項目進行適配(ruoyi舉例) (1) 在路由文件添加需要被外鏈的vue頁面配置 // 若依項目的話是 router/index.js文件 {path: /contrast,component: () > import(/views/contrast/index),hidden: true },(2) 開放白名單 // 若依項目的話是 permission.js 文件 cons…

【DeepSeek】5分鐘快速實現本地化部署教程

一、快捷部署 &#xff08;1&#xff09;下載ds大模型安裝助手&#xff0c;下載后直接點擊快速安裝即可。 https://file-cdn-deepseek.fanqiesoft.cn/deepseek/deepseek_28348_st.exe &#xff08;2&#xff09;打開軟件&#xff0c;點擊立即激活 &#xff08;3&#xff09;選…

Linux第一課

如何在Windows系統上安裝紅帽Linux虛擬機 一:下載VNware 下載鏈接:Desktop Hypervisor Solutions | VMware 二:下載操作系統鏡像文件 在阿里云開源鏡像站下載(本文章下載 red hat 9.3) 阿里云開源鏡像站鏈接:阿里巴巴開源鏡像站-OPSX鏡像站-阿里云開發者社區 三:創建虛擬機文…

語音分離:使用短時能量提取主聲源

語音分離模型&#xff1a;mossfomer2 計算短時能量 def compute_short_time_energy(audio: np.ndarray, frame_size: int, hop_size: int) -> np.ndarray:"""計算音頻信號的短時能量 將音頻分為若干幀&#xff0c;每一幀長度為 frame_size, 幀與幀之間以 h…

【VUE】第二期——生命周期及工程化

目錄 1 生命周期 1.1 介紹 1.2 鉤子 2 可視化圖表庫 3 腳手架Vue CLI 3.1 使用步驟 3.2 項目目錄介紹 3.3 main.js入口文件代碼介紹 4 組件化開發 4.1 組件 4.2 普通組件注冊 4.2.1 局部注冊 4.2.2 全局注冊 1 生命周期 1.1 介紹 Vue生命周期&#xff1a;就是…

SyntaxError: Unexpected keyword ‘else‘

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

Spring Boot靜態資源訪問順序

在 Spring Boot 中&#xff0c;static 和 public 目錄都用于存放靜態資源&#xff08;如 HTML、CSS、JavaScript、圖片等文件&#xff09;&#xff0c;但它們在使用上有一些細微的區別。以下是它們的詳細對比&#xff1a; 1. 默認優先級 Spring Boot 會按照以下優先級加載靜態…