一,职责链模式的定义
职责链模式,又被称为责任链模式,是一种行为型设计模式,它让多个对象依次处理收到的请求,直到处理完成为止。
职责链模式需要使用多个对象,其中的每个对象要么处理请求,要么将请求传递给下一个对象,该模式因此可以实现发送方与接收方的松散耦合。
在职责链模式中,一个对象可以被理解为处理器,每个处理器都包含对下一个处理器的引用,多个对象之间形成了一个链表的结构。
职责链模式在现实生活中的抽象实例:
审批流程:在流程中,当一个申请需要多级审批时,可以使用职责链模式。每一级审批者都是职责链的一部分。
银行账户验证:在银行系统中,需要对用户进行身份验证和授权操作,而验证操作涉及多个步骤。
异常处理:在程序开发中,每个异常处理器可以处理特定类型的异常,如果当前处理器无法解决,则传递给下一个处理器。
二,职责链模式的结构
职责链模式主要包含以下组件:
1.抽象处理器(Handler):
处理器的抽象类,声明处理请求的抽象接口,并持有对下一个处理器的引用。
2.具体处理器(ConcreteHandler):
继承自抽象处理器,包含了对处理请求接口的具体实现,负责处理特定类型的请求或将请求传递给下一个处理器。
3.客户端(Client):
负责创建处理器的实例,并将它们加入到职责链中。然后向第一个处理器发送请求,并等待职责链的返回结果。
组件之间的工作步骤如下:
1.客户端将请求传递给职责链中的第一个处理器。
2.第一个处理器尝试处理请求。如果处理成功,则结束处理过程并返回结果,如果无法处理,则将请求转发给下一个处理器。
3.下一个处理器重复步骤2,直到找到能够处理请求的处理器,或者职责链中没有更多的处理器。
4.客户端获得处理结果。
对应UML类图:
三,职责链模式代码样例
#include <iostream>
#include <string>
class Handler
{
protected:
Handler* successor;
public:
void setSuccessor(Handler* successor)
{
this->successor = successor;
}
virtual void handleRequest(const std::string& request) = 0;
};
class ConcreteHandler1 : public Handler
{
public:
void handleRequest(const std::string& request) override
{
if (request == "Type1")
{
std::cout << "Handling request of type Type1." << std::endl;
}
else if (successor != nullptr)
{
successor->handleRequest(request);
}
else
{
std::cout << "Unable to handle the request." << std::endl;
}
}
};
class ConcreteHandler2 : public Handler
{
public:
void handleRequest(const std::string& request) override
{
if (request == "Type2")
{
std::cout << "Handling request of type Type2." << std::endl;
}
else if (successor != nullptr)
{
successor->handleRequest(request);
}
else
{
std::cout << "Unable to handle the request." << std::endl;
}
}
};
class ConcreteHandler3 : public Handler
{
public:
void handleRequest(const std::string& request) override
{
if (request == "Type3")
{
std::cout << "Handling request of type Type3." << std::endl;
}
else if (successor != nullptr)
{
successor->handleRequest(request);
}
else
{
std::cout << "Unable to handle the request." << std::endl;
}
}
};
int main()
{
Handler* handler1 = new ConcreteHandler1();
Handler* handler2 = new ConcreteHandler2();
Handler* handler3 = new ConcreteHandler3();
handler1->setSuccessor(handler2);
handler2->setSuccessor(handler3);
handler1->handleRequest("Type2");
handler1->handleRequest("Type3");
handler1->handleRequest("Type4");
delete handler1;
delete handler2;
delete handler3;
return 0;
}
运行结果:
Handling request of type Type2.
Handling request of type Type3.
Unable to handle the request.
四,职责链模式的应用场景
命令处理器:比如在游戏或GUI应用中,用户可以发送各种操作命令,如“播放音乐”、“关闭窗口”,而具体执行过程由一系列处理器完成。
日志记录器:将不同严重等级的日志交给不同的处理器去打印。
Web服务开发:在Web服务中,对请求进行校验和过滤,如权限验证、数据校验等。
权限控制:在用户权限管理中,可以根据角色的不同职责分配不同的权限验证步骤。
消息路由:在网络通信中,将不同类型的消息分别发送给不同的处理程序。
五,职责链模式的优缺点
职责链模式的优点:
和命令模式类似,可以实现发送者和接收者的解耦。
灵活性强,可以修改职责链中的结构和顺序。
有扩展性,可以在最小改动的情况下添加新的处理器。
处理器可以在不同的职责链中重复使用。
职责链模式的缺点:
对请求的处理可能覆盖不全,导致bug的产生。
请求的处理过程十分冗长。
请求的传递涉及多个对象,性能开销大。
责任链需要被一直维护和管理。
六,代码实战
Demo1:日志记录器
#include <iostream>
#include <string>
#include <vector>
//Logger接口
class Logger {
public:
virtual void log(const std::string& message) = 0;
};
//处理正常日志
class InfoLogger: public Logger{
public:
void log(const std::string& message) override {
std::cerr << "Info: " << message << std::endl;
}
};
//处理调试日志
class DebugLogger: public Logger{
public:
void log(const std::string& message) override {
std::cout << "Debug: " << message << std::endl;
}
};
//处理错误日志
class ErrorLogger: public Logger{
public:
void log(const std::string& message) override {
std::cerr << "Error: " << message << std::endl;
}
};
class LoggingChain {
private:
std::vector<std::shared_ptr<Logger>> loggers;
public:
void addLogger(std::shared_ptr<Logger> logger) {
loggers.push_back(logger);
}
void log(const std::string& message) {
for (auto it = loggers.rbegin(); it != loggers.rend(); ++it) {
(*it)->log(message);
}
}
};
int main() {
LoggingChain chain;
chain.addLogger(std::make_shared<InfoLogger>());
chain.addLogger(std::make_shared<DebugLogger>());
chain.addLogger(std::make_shared<ErrorLogger>());
chain.log("This is a test message.");
return 0;
}
运行结果:
Error: This is a test message.
Debug: This is a test message.
Info: This is a test message.
Demo2:模拟消息接收
#include <iostream>
#include <string>
#include <vector>
class Message {
public:
virtual ~Message() {}
};
class TextMessage : public Message {
};
class ImageMessage : public Message {
};
class MessageHandler{
public:
virtual void handle(Message* msg) = 0;
};
class TextProcessor: public MessageHandler{
public:
void handle(Message* msg) override{
if (dynamic_cast<TextMessage*>(msg)) {
std::cout << "handling a text message." << std::endl;
process(*static_cast<TextMessage*>(msg));
}
else {
forward(msg);
}
}
private:
void process(TextMessage& msg) {
}
void forward(Message* msg) {
}
};
class ImageProcessor: public MessageHandler{
public:
void handle(Message* msg) override {
if (dynamic_cast<ImageMessage*>(msg)) {
std::cout << "handling an image message." << std::endl;
process(*static_cast<ImageMessage*>(msg));
}
else {
forward(msg);
}
}
private:
void process(ImageMessage& img){
}
void forward(Message* msg){
}
};
class ChainOfResponsibility {
public:
void setHandler(MessageHandler* handler){
current_ = handler;
}
void handle(Message* msg) {
current_->handle(msg);
}
private:
MessageHandler* current_ = nullptr;
};
int main() {
ChainOfResponsibility chain;
TextProcessor txtProc;
ImageProcessor imgProc;
chain.setHandler(&txtProc);
chain.handle(new TextMessage());
chain.setHandler(&imgProc);
chain.handle(new ImageMessage());
return 0;
}
运行结果:
handling a text message.
handling an image message.
七,参考阅读
https://www.geeksforgeeks.org/chain-responsibility-design-pattern/
https://www.tutorialspoint.com/design_pattern/chain_of_responsibility_pattern.htm
https://sourcemaking.com/design_patterns/chain_of_responsibility