職責鏈模式(Chain of Responsibility)詳解
一、核心概念
職責鏈模式將請求的發送者和接收者解耦,使多個對象都有機會處理請求。這些對象連接成一條鏈,請求沿著鏈傳遞,直到有一個對象處理它為止。該模式允許動態調整處理者的順序或組合,增強系統靈活性。
核心組件:
- 抽象處理者(Handler):定義處理請求的接口,包含對下一個處理者的引用。
- 具體處理者(Concrete Handler):實現處理請求的方法,決定是否處理請求或將其傳遞給下一個處理者。
- 客戶端(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;
}
三、職責鏈模式的優勢
-
解耦發送者和接收者:
- 請求者無需知道哪個對象處理請求,只需將請求發送到鏈上。
-
動態組合處理者:
- 可在運行時動態調整處理者的順序或組成。
-
簡化對象職責:
- 每個處理者只需關注自己的職責,無需關心整條鏈的結構。
-
增強可擴展性:
- 新增處理者只需實現接口并加入鏈中,無需修改現有代碼。
四、實現變種
-
純職責鏈 vs 不純職責鏈:
- 純職責鏈:每個處理者要么處理請求,要么完全不處理(如示例)。
- 不純職責鏈:處理者可部分處理請求后繼續傳遞(如日志過濾)。
-
動態鏈構建:
- 通過配置文件或工廠動態構建責任鏈,適應不同場景。
-
并行鏈處理:
- 多個處理者同時處理請求,返回首個成功的結果(如負載均衡)。
五、適用場景
-
多級審批系統:
- 如請假、報銷等流程,根據金額或權限自動分配審批人。
-
事件處理系統:
- 如GUI事件傳遞(按鈕點擊→容器→窗口)。
-
日志過濾系統:
- 根據日志級別(INFO→WARN→ERROR)選擇處理方式。
-
請求攔截器:
- 如Web應用中的過濾器鏈(身份驗證→日志記錄→權限檢查)。
六、注意事項
-
鏈的完整性:
- 確保鏈的末端有默認處理者,避免請求無人處理。
-
性能問題:
- 過長的鏈可能影響性能,需控制鏈的長度。
-
調試難度:
- 鏈的動態性可能導致調試困難,需添加適當的日志。
-
與狀態模式的區別:
- 職責鏈模式中處理者可自由決定是否傳遞請求;狀態模式中狀態轉移由上下文控制。
職責鏈模式通過將請求處理者組織成鏈,實現了請求發送者與接收者的解耦,使系統更具靈活性和可維護性。在需要動態處理請求或多級處理的場景中,該模式尤為適用。
中介者模式(Mediator Pattern)詳解
一、核心概念
中介者模式通過一個中介對象來封裝一系列對象間的交互,使各對象無需顯式引用彼此,從而降低耦合度。中介者負責協調對象間的通信,所有交互都通過中介者進行,而非對象直接調用。
核心組件:
- 抽象中介者(Mediator):定義協調對象交互的接口。
- 具體中介者(Concrete Mediator):實現中介者接口,維護對象引用并處理交互邏輯。
- 抽象同事類(Colleague):定義同事對象的公共接口,持有中介者引用。
- 具體同事類(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;
}
三、中介者模式的優勢
-
降低耦合度:
- 對象間無需直接引用,所有交互通過中介者,減少依賴。
-
集中控制交互:
- 中介者作為交互中心,便于統一管理和修改交互邏輯。
-
增強可擴展性:
- 新增同事或修改交互邏輯只需調整中介者,無需修改所有同事類。
-
簡化對象設計:
- 同事類只需關注自身業務邏輯,無需處理復雜的交互關系。
四、實現變種
-
事件總線(Event Bus):
- 中介者維護事件隊列,同事通過發布/訂閱機制通信(如Guava EventBus)。
-
MVC模式中的Controller:
- Controller作為View和Model的中介者,處理兩者間的交互。
-
分布式系統中的消息隊列:
- 如RabbitMQ、Kafka作為服務間的中介者,實現解耦通信。
五、適用場景
-
對象間交互復雜:
- 如GUI組件間的交互(按鈕、文本框、下拉菜單)。
-
網狀結構轉星型結構:
- 將多對多關系轉化為一對多關系,如社交網絡中的好友關系。
-
系統模塊間松耦合:
- 如電商系統中訂單、庫存、支付模塊的交互。
-
需要集中控制的場景:
- 如多人游戲中的房間管理、交通調度系統。
六、注意事項
-
中介者復雜度:
- 中介者可能變得過于龐大,需合理拆分功能或采用分層中介者。
-
單點故障風險:
- 中介者作為核心組件,若出現故障可能影響整個系統。
-
性能開銷:
- 所有交互通過中介者中轉,可能引入性能瓶頸。
-
與觀察者模式的區別:
- 中介者模式中同事對象依賴中介者;觀察者模式中觀察者與被觀察對象松耦合。
中介者模式通過引入中介對象,將復雜的對象間交互集中管理,降低了系統耦合度,提高了可維護性。在需要控制對象間直接通信的場景中,該模式尤為有效。