目录

一、引言
举个例子,小明是公司的一名员工,最近身体不舒服,需要请假一个月。他拿着请假条,先去找小组长签字。小组长签完字后,让他拿着请假条去找部门经理签字。部门经理签完字后,又让他拿着请假条去找总经理签字。直到总经理也签了字,小明的请假才算正式获批。
后来小明得知,请假天数在3天以内,直接找小组长签字即可,3~7天需要小组长和部门经理签字,超过7天需要小组长、部门经理和总经理签字。
所以,以上的处理过程,客户端代码的逻辑如下:

可以看到,在客户端是需要做出很多判断的。如果处理链条一改变,比如多了老板审批这一步的话,客户端是需要再加一个判断的。好的代码应该是高内聚低耦合的,也就是说,处理模块的改变不影响到客户端。追求的是小明一旦提交了请假申请,那么他只需要等待结果就好了,而不用跑去问这个哪个的。在这种场景下,应用责任链模式就很合适。
二、模式定义与核心思想
责任链模式的定义就是,避免将请求的发送者与接收者耦合,让多个对象都有机会处理请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

三、责任链模式的纯与不纯
经典的责任链模式为,当请求沿着处理链传递时,一旦有处理器可以对该请求进行处理,那么就不再继续往后传递。上面给出的定义就是经典责任链模式的定义,或者说是纯的责任链模式。与之对应的就是不纯的责任链模式。不纯的责任链模式就是,处理器可以处理请求的一部分,然后继续传递给下一个处理器。引言中请假的例子就是不纯的责任链模式。不管是纯与不纯,不论好坏,都有各自的应用场景,我们该关心的是这两种模式哪一种能更好的解决我们的问题。
四、模式结构与组件
责任链模式的结构和组件基本上是固定的,一个抽象的处理类,若干个具体处理类继承这个抽象的处理类,然后一个客户端发起请求。

五、代码样例
下面通过一个例子来说明:
需求:我们有一个文本处理的责任链,处理链中有两个处理器:
- 清除首尾空格处理器(TrimProcessor):清除文本首尾空格(部分处理),然后传递给下一个处理器。
- 大写处理器(UpperProcessor):将文本转为大写(另一种处理)。
处理过程: 输入: " hello world " 经过TrimProcessor:变成"hello world"(去除了首尾空格) 然后传递给UpperProcessor:变成"HELLO WORLD"。
cpp
//chain.hpp
#ifndef chain_hpp
#define chain_hpp
#include <iostream>
#include <memory>
#include <string>
#include <algorithm>
class Request {
public:
Request(std::string data) : _data(data) {}
std::string getData() {
return _data;
}
void setData(std::string &data) {
_data = data;
}
private:
std::string _data;
};
class Processor {
public:
Processor() : _next(nullptr) {}
virtual void handleRequest(Request &request) = 0;
void setNext(const std::shared_ptr<Processor> &next) {
this->_next = next;
}
protected:
std::shared_ptr<Processor> _next;
};
class TrimProcessor : public Processor {
public:
void handleRequest(Request &request) override {
std::string data = request.getData();
std::string result = trim(data);
request.setData(result);
if (_next) {
_next->handleRequest(request);
}
}
private:
std::string trim(const std::string &data) {
size_t first = data.find_first_not_of(' ');
if (first == std::string::npos) {
return "";
}
size_t last = data.find_last_not_of(' ');
return data.substr(first, last - first + 1);
}
};
class UpperProcessor : public Processor {
public:
void handleRequest(Request &request) override {
std::string data = request.getData();
std::string result = toUpperCase(data);
request.setData(result);
}
private:
std::string toUpperCase(const std::string &data) {
std::string result;
for (auto &c : data) {
result += toupper(c);
}
return result;
}
};
#endif /* chain_hpp */
//main.cc
#include "chain.hpp"
int main()
{
std::shared_ptr<Processor> chain = std::make_shared<TrimProcessor>();
chain->setNext(std::make_shared<UpperProcessor>());
Request request(" -hello world- ");
chain->handleRequest(request);
std::cout << request.getData() << std::endl; // Output: HELLO WORLD
return 0;
}
六、优缺点分析
优点:
- 将请求的发送者和处理者解耦。
- 可以灵活的增减处理器。
- 符合开闭原则。
缺点:
- 缺少尾处理器,有的请求可能无法处理------添加默认处理器兜底。
- 处理链过长,会影响到性能------控制处理链长度。
- 避免循环引用。
七、结语
责任链模式如同装配流水线,让请求在不同工位间流转处理。掌握这一设计模式,在遇到相应的场景时,可以迅速提升我们代码的逼格。
完~