設計模式(九)

職責鏈模式(Chain of Responsibility)詳解

一、核心概念

職責鏈模式將請求的發送者和接收者解耦,使多個對象都有機會處理請求。這些對象連接成一條鏈,請求沿著鏈傳遞,直到有一個對象處理它為止。該模式允許動態調整處理者的順序或組合,增強系統靈活性。

核心組件

  1. 抽象處理者(Handler):定義處理請求的接口,包含對下一個處理者的引用。
  2. 具體處理者(Concrete Handler):實現處理請求的方法,決定是否處理請求或將其傳遞給下一個處理者。
  3. 客戶端(Client):將請求發送到鏈的起始處理者。
二、代碼示例:員工請假審批系統

場景:員工請假需要不同層級的領導審批(組長→經理→總監),根據請假天數自動選擇審批者。

#include <iostream>
#include <memory>// 請假請求
class LeaveRequest {
private:int days;std::string name;public:LeaveRequest(const std::string& name, int days) : name(name), days(days) {}int getDays() const { return days; }std::string getName() const { return name; }
};// 抽象處理者:領導
class Leader {
protected:std::shared_ptr<Leader> nextLeader;  // 指向下一個處理者public:virtual void setNextLeader(std::shared_ptr<Leader> leader) {nextLeader = leader;}virtual void handleRequest(const LeaveRequest& request) = 0;virtual ~Leader() = default;
};// 具體處理者:組長
class TeamLeader : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 3) {std::cout << "組長批準" << request.getName() << "請假" << request.getDays() << "天" << std::endl;} else if (nextLeader) {std::cout << "組長無法處理,轉交上級..." << std::endl;nextLeader->handleRequest(request);} else {std::cout << "請假天數過長,無人處理" << std::endl;}}
};// 具體處理者:經理
class Manager : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 7) {std::cout << "經理批準" << request.getName() << "請假" << request.getDays() << "天" << std::endl;} else if (nextLeader) {std::cout << "經理無法處理,轉交上級..." << std::endl;nextLeader->handleRequest(request);} else {std::cout << "請假天數過長,無人處理" << std::endl;}}
};// 具體處理者:總監
class Director : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 15) {std::cout << "總監批準" << request.getName() << "請假" << request.getDays() << "天" << std::endl;} else {std::cout << "請假天數超過15天,拒絕批準" << std::endl;}}
};// 客戶端代碼
int main() {// 創建處理者auto teamLeader = std::make_shared<TeamLeader>();auto manager = std::make_shared<Manager>();auto director = std::make_shared<Director>();// 構建責任鏈teamLeader->setNextLeader(manager);manager->setNextLeader(director);// 提交請假請求LeaveRequest request1("張三", 2);teamLeader->handleRequest(request1);LeaveRequest request2("李四", 5);teamLeader->handleRequest(request2);LeaveRequest request3("王五", 10);teamLeader->handleRequest(request3);LeaveRequest request4("趙六", 20);teamLeader->handleRequest(request4);return 0;
}
三、職責鏈模式的優勢
  1. 解耦發送者和接收者

    • 請求者無需知道哪個對象處理請求,只需將請求發送到鏈上。
  2. 動態組合處理者

    • 可在運行時動態調整處理者的順序或組成。
  3. 簡化對象職責

    • 每個處理者只需關注自己的職責,無需關心整條鏈的結構。
  4. 增強可擴展性

    • 新增處理者只需實現接口并加入鏈中,無需修改現有代碼。
四、實現變種
  1. 純職責鏈 vs 不純職責鏈

    • 純職責鏈:每個處理者要么處理請求,要么完全不處理(如示例)。
    • 不純職責鏈:處理者可部分處理請求后繼續傳遞(如日志過濾)。
  2. 動態鏈構建

    • 通過配置文件或工廠動態構建責任鏈,適應不同場景。
  3. 并行鏈處理

    • 多個處理者同時處理請求,返回首個成功的結果(如負載均衡)。
五、適用場景
  1. 多級審批系統

    • 如請假、報銷等流程,根據金額或權限自動分配審批人。
  2. 事件處理系統

    • 如GUI事件傳遞(按鈕點擊→容器→窗口)。
  3. 日志過濾系統

    • 根據日志級別(INFO→WARN→ERROR)選擇處理方式。
  4. 請求攔截器

    • 如Web應用中的過濾器鏈(身份驗證→日志記錄→權限檢查)。
六、注意事項
  1. 鏈的完整性

    • 確保鏈的末端有默認處理者,避免請求無人處理。
  2. 性能問題

    • 過長的鏈可能影響性能,需控制鏈的長度。
  3. 調試難度

    • 鏈的動態性可能導致調試困難,需添加適當的日志。
  4. 與狀態模式的區別

    • 職責鏈模式中處理者可自由決定是否傳遞請求;狀態模式中狀態轉移由上下文控制。

職責鏈模式通過將請求處理者組織成鏈,實現了請求發送者與接收者的解耦,使系統更具靈活性和可維護性。在需要動態處理請求或多級處理的場景中,該模式尤為適用。

中介者模式(Mediator Pattern)詳解

一、核心概念

中介者模式通過一個中介對象來封裝一系列對象間的交互,使各對象無需顯式引用彼此,從而降低耦合度。中介者負責協調對象間的通信,所有交互都通過中介者進行,而非對象直接調用。

核心組件

  1. 抽象中介者(Mediator):定義協調對象交互的接口。
  2. 具體中介者(Concrete Mediator):實現中介者接口,維護對象引用并處理交互邏輯。
  3. 抽象同事類(Colleague):定義同事對象的公共接口,持有中介者引用。
  4. 具體同事類(Concrete Colleague):實現抽象同事類,通過中介者與其他同事通信。

沒有使用中介模式前是網狀結構,關系混亂

現在改為輻射狀,變為多對一

二、代碼示例:機場塔臺調度系統

場景:飛機降落和起飛需要塔臺協調,避免跑道沖突。飛機(同事)不直接通信,而是通過塔臺(中介者)調度。

#include <iostream>
#include <string>
#include <memory>
#include <vector>// 前向聲明
class Tower;// 抽象同事類:飛機
class Aircraft {
protected:Tower* tower;std::string flightNumber;public:Aircraft(Tower* tower, const std::string& flightNumber) : tower(tower), flightNumber(flightNumber) {}virtual void requestLanding() = 0;virtual void confirmLanding() = 0;virtual std::string getFlightNumber() const = 0;virtual ~Aircraft() = default;
};// 抽象中介者:塔臺
class Tower {
public:virtual void registerAircraft(Aircraft* aircraft) = 0;virtual void handleLandingRequest(Aircraft* aircraft) = 0;virtual void clearRunway() = 0;virtual ~Tower() = default;
};// 具體同事類:客機
class PassengerAircraft : public Aircraft {
public:using Aircraft::Aircraft;  // 繼承構造函數void requestLanding() override {std::cout << "[" << flightNumber << "] 請求降落" << std::endl;tower->handleLandingRequest(this);}void confirmLanding() override {std::cout << "[" << flightNumber << "] 確認降落,跑道清空" << std::endl;}std::string getFlightNumber() const override { return flightNumber; }
};// 具體同事類:貨機
class CargoAircraft : public Aircraft {
public:using Aircraft::Aircraft;  // 繼承構造函數void requestLanding() override {std::cout << "[" << flightNumber << "] 請求降落" << std::endl;tower->handleLandingRequest(this);}void confirmLanding() override {std::cout << "[" << flightNumber << "] 確認降落,跑道清空" << std::endl;}std::string getFlightNumber() const override { return flightNumber; }
};// 具體中介者:控制塔臺
class ControlTower : public Tower {
private:std::vector<Aircraft*> aircrafts;bool runwayAvailable = true;public:void registerAircraft(Aircraft* aircraft) override {aircrafts.push_back(aircraft);std::cout << "塔臺已注冊航班: " << aircraft->getFlightNumber() << std::endl;}void handleLandingRequest(Aircraft* aircraft) override {if (runwayAvailable) {runwayAvailable = false;std::cout << "塔臺: 跑道可用," << aircraft->getFlightNumber() << " 可以降落" << std::endl;aircraft->confirmLanding();} else {std::cout << "塔臺: 跑道繁忙," << aircraft->getFlightNumber() << " 請等待" << std::endl;}}void clearRunway() override {runwayAvailable = true;std::cout << "塔臺: 跑道已清空,可以接受新降落請求" << std::endl;}
};// 客戶端代碼
int main() {auto tower = std::make_unique<ControlTower>();auto plane1 = std::make_unique<PassengerAircraft>(tower.get(), "CA1234");auto plane2 = std::make_unique<CargoAircraft>(tower.get(), "CZ5678");auto plane3 = std::make_unique<PassengerAircraft>(tower.get(), "MU9012");tower->registerAircraft(plane1.get());tower->registerAircraft(plane2.get());tower->registerAircraft(plane3.get());// 模擬多個飛機同時請求降落plane1->requestLanding();plane2->requestLanding();plane3->requestLanding();// 跑道清空后再次請求tower->clearRunway();plane2->requestLanding();return 0;
}
三、中介者模式的優勢
  1. 降低耦合度

    • 對象間無需直接引用,所有交互通過中介者,減少依賴。
  2. 集中控制交互

    • 中介者作為交互中心,便于統一管理和修改交互邏輯。
  3. 增強可擴展性

    • 新增同事或修改交互邏輯只需調整中介者,無需修改所有同事類。
  4. 簡化對象設計

    • 同事類只需關注自身業務邏輯,無需處理復雜的交互關系。
四、實現變種
  1. 事件總線(Event Bus)

    • 中介者維護事件隊列,同事通過發布/訂閱機制通信(如Guava EventBus)。
  2. MVC模式中的Controller

    • Controller作為View和Model的中介者,處理兩者間的交互。
  3. 分布式系統中的消息隊列

    • 如RabbitMQ、Kafka作為服務間的中介者,實現解耦通信。
五、適用場景
  1. 對象間交互復雜

    • 如GUI組件間的交互(按鈕、文本框、下拉菜單)。
  2. 網狀結構轉星型結構

    • 將多對多關系轉化為一對多關系,如社交網絡中的好友關系。
  3. 系統模塊間松耦合

    • 如電商系統中訂單、庫存、支付模塊的交互。
  4. 需要集中控制的場景

    • 如多人游戲中的房間管理、交通調度系統。
六、注意事項
  1. 中介者復雜度

    • 中介者可能變得過于龐大,需合理拆分功能或采用分層中介者。
  2. 單點故障風險

    • 中介者作為核心組件,若出現故障可能影響整個系統。
  3. 性能開銷

    • 所有交互通過中介者中轉,可能引入性能瓶頸。
  4. 與觀察者模式的區別

    • 中介者模式中同事對象依賴中介者;觀察者模式中觀察者與被觀察對象松耦合。

中介者模式通過引入中介對象,將復雜的對象間交互集中管理,降低了系統耦合度,提高了可維護性。在需要控制對象間直接通信的場景中,該模式尤為有效。

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

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

相關文章

左神算法之Zigzag方式打印矩陣

目錄 Zigzag方式打印矩陣1. 題目2. 解釋3. 思路4. 代碼5. 總結 Zigzag方式打印矩陣 1. 題目 用zigzag的方式打印矩陣&#xff0c;比如下面的矩陣&#xff1a; 0 1 2 3 4 5 6 7 8 9 10 11打印順序為&#xff1a;0 1 4 8 5 2 3 6 9 10 7 11 2. 解釋 Zigzag打印矩陣是指按照…

【前端批量下載圖片,并打包成壓縮包下載】

一、需求說明 我現在有個需求&#xff1a; 1.列表中有個下載按鈕&#xff0c;點擊下載&#xff0c;將列表中所有的圖片打成壓縮包&#xff0c;并下載 2.效果演示點擊查看效果 最終效果&#xff1a; 二、安裝下載插件 實現此功能需要兩個插件&#xff1a;jszip、file-saver …

NV133NV137美光固態閃存NV147NV148

NV133NV137美光固態閃存NV147NV148 美光固態閃存技術矩陣深度解析&#xff1a;NV133至NV148的全面較量 一、性能參數&#xff1a;數據高速公路的“車速”比拼 讀寫速度&#xff1a;從“鄉間小道”到“高鐵動脈” 美光NV系列固態閃存的核心競爭力在于其讀寫速度的躍升。以NV15…

從LLM到WM:大語言模型如何進化成具身世界模型?

1.引言這學期在方老師開設的《機器人大模型基礎和前沿》選修課上接觸并學習了具身智能方面的相關知識。作為交互組的組長&#xff0c;我和組員們在幻爾機器狗的功能開發上有切身的實踐與探索&#xff0c;在張江具身智能大會上&#xff0c;也見識到了前沿的技術和行業的發展現狀…

第十六屆藍橋杯C++B組國賽題解+復盤總結

文章目錄 寫在前面1、新型鎖2、互質藏卡3、數字輪盤4、斐波那契字符串5、項鏈排列6、藍橋星數字7、翻倍8、近似回文字符串9、子串去重10、涂格子 寫在前面 打了三年&#xff0c;第十六屆是我最后一次參加了&#xff0c;終于如愿以償國一啦。 這場的大多題目都補了&#xff0c;…

【TTS】2024-2025年主流開源TTS模型的綜合對比分析

以下是針對2024-2025年主流開源與商用TTS模型的綜合技術選型分析&#xff0c;結合GitHub熱度、功能特性、部署成本及中文支持等核心維度進行對比&#xff0c;并附詳細實踐建議。 一、開源TTS模型對比&#xff08;2024-2025年主流方案&#xff09; 模型名稱開源/廠商克隆支持中…

redis延時雙刪,為什么第一次刪除

Redis延時雙刪策略中第一次刪除的作用 在緩存與數據庫一致性方案中&#xff0c;"延時雙刪"&#xff08;Delayed Double-Delete&#xff09;是一種經典策略&#xff0c;其核心流程如下&#xff1a; 第一次刪除&#xff1a;更新數據庫前&#xff0c;先刪除緩存 更新數…

深度學習1(深度學習和機器學習的區別,神經網絡)

深度學習和機器學習的區別 深度學習和機器學習都是人工智能&#xff08;AI&#xff09;的重要分支&#xff0c;但它們在方法、應用場景和技術細節上有顯著區別。 機器學習通過算法讓計算機從數據中學習規律&#xff0c;并做出預測或決策。核心是特征工程&#xff08;人工提取數…

這才叫窗口查詢!TDEngine官方文檔沒講透的實戰玩法

第1章&#xff1a;你不知道的TDEngine窗口查詢——開局就不簡單 先別急著翻白眼&#xff0c;提到時間窗口查詢&#xff0c;可能你腦子里立馬浮現的就是那些常規套路&#xff1a;GROUP BY time_interval、FIRST()、LAST()&#xff0c;再加上點AVG()和MAX()&#xff0c;一鍋端。…

Day50 預訓練模型+CBAM模塊

目錄 一、resnet結構解析 二、CBAM放置位置的思考 三、針對預訓練模型的訓練策略 a.差異化學習率 b.三階段式解凍與微調 (Progressive Unfreezing) 四、嘗試對vgg16cbam進行微調策略 是否可以對于預訓練模型增加模塊來優化其效果&#xff0c;這里會遇到一個問題&#xff…

快速說一下TDD BDD DDD

基本概念 TDD&#xff08;測試驅動開發&#xff09;、BDD&#xff08;行為驅動開發&#xff09;和 DDD&#xff08;領域驅動設計&#xff09;是軟件開發領域中幾個重要的概念&#xff0c;它們各自有著獨特的側重點與應用場景&#xff0c;以下為你詳細介紹&#xff1a; 測試驅…

淺析基于深度學習算法的英文OCR技術工作原理及其應用場景

在數字化信息飛速發展的當下&#xff0c;大量的文本信息以各種形式存在&#xff0c;從傳統的紙質文檔到電子圖片中的文字內容。如何高效地將這些非結構化的文本轉化為計算機能夠理解和處理的格式&#xff0c;成為了提高信息處理效率的關鍵。英文 OCR&#xff08;Optical Charac…

AI時代SEO關鍵詞策略

內容概要 在人工智能&#xff08;AI&#xff09;驅動的新時代&#xff0c;搜索引擎優化&#xff08;SEO&#xff09;關鍵詞策略正迎來顛覆性變革。本篇文章將系統解析AI技術如何重塑關鍵詞研究、內容優化及流量提升的全過程&#xff0c;幫助企業實現高效可持續的在線曝光。通過…

免費一鍵自動化申請、續期、部署、監控所有 SSL/TLS 證書,ALLinSSL開源免費的 SSL 證書自動化管理平臺

目錄 一、前言二、ALLinSSL 簡介亮點核心功能 三、操作步驟部署安裝授權DNS服務商授權你的主機服務器自動化部署ssl測試自動申請ssl證書 一、前言 SSL證書是每個網站必備的&#xff0c;但是現在的免費的ssl證書有效期是3個月&#xff0c;以后CA/B Forum 調整 SSL 證書最長有效期…

如何高效清理C盤、釋放存儲空間,讓電腦不再卡頓。

以下是針對Windows系統的C盤深度清理全攻略&#xff0c;包含系統級優化和進階操作&#xff0c;可釋放30%-70%的冗余空間&#xff1a; 一、系統自帶工具快速清理&#xff08;5分鐘見效&#xff09; 磁盤清理工具 按WinR → 輸入cleanmgr → 選擇C盤重點勾選&#xff1a; ? Wind…

AI 如何批量提取 Word 表格中的字段數據到 Excel 中?

在日常工作中&#xff0c;我們經常會接觸到大量 Word 表格——學生登記表、客戶信息表、報名信息表……這些表格數據往往格式不一&#xff0c;但有一個共同的需求&#xff1a; 從中提取出“字段-值”結構&#xff0c;統一導入 Excel&#xff0c;方便后續分析處理。 傳統手工操作…

github代碼中遇到的問題-解決方案

下面內容介紹的是我個人在復現github代碼遇到的一些問題&#xff0c;如果也可以幫到你&#xff0c;請點個關注吧~ 1.我的項目位置在D盤&#xff0c;但是為什么下面終端的位置在E盤 -》cd /d D:\Users\xxxx&#xff08;后面的xxxx是你具體的文檔位置&#xff09; 2.怎么知道我…

使用Visual Studio 2022創建CUDA編程項目

要在 Visual Studio 2022 中開發 CUDA 程序,需要進行環境配置并了解基本開發流程。以下是詳細步驟: 環境準備 安裝 Visual Studio 2022 下載并安裝 Visual Studio 2022(社區版或專業版均可)。安裝時勾選 “使用 C++ 的桌面開發” 工作負載。確保安裝 “C++ CMake 工具” …

Java測試題一

1.基本數據類型有哪些&#xff1f; 基本數據類型有8個&#xff1a;整數&#xff1a;byte、int、long、short。 浮點型&#xff1a;float、double。 布爾型boolean。 字符型&#xff1a;char 2.下列代碼的輸出是什么&#xff1f;為什么&#xff1f; public static void ma…

使用 Flask 構建基于 Dify 的企業資金投向與客戶分類評估系統

使用 Flask 構建基于 Dify 的企業資金投向與客戶分類評估系統 前言一、&#x1f9e9; 技術棧二、&#x1f4e6; 項目結構概覽三、 &#x1f527; 核心功能模塊說明1 配置參數2 請求封裝函數? 功能說明&#xff1a; 3 Prompt 構造函數4 Flask 路由定義&#x1f3e0; 首頁路由 /…