一、背景
当一个请求需要经过多个节点的处理,如果不考虑任何模式,每个对象要根据是否符合条件来决定是不是自己处理,这样就要使用if-else去处理。确定了类似A->B->C->D的处理流程后就不能再修改(除非修改源代码),导致客户端无法定制处理流程。再者各个节点的处理流程集中在一个类中,违反了“单一职责原则”,将导致测试和维护难度加大;最后无法在运行时动态的增加、修改或者删除处理流程中的处理节点,灵活性缺失。
二、模式定义
责任链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象能够处理它为止。发送请求的客户端并不知道链上的哪个对象会处理这个请求,这使得系统在不影响客户端的情况下动态的组织和分配责任。
模式分析
- 可以将责任链想象成数据结构中的链表以更好理解。
- 每个接收者都包含另一个接收者的引用,如果当前对象不能处理该请求,它将请求传给下一个接收者。
- 职责链可以是一条直线、一个环链或是一个树结构的一部分,需要根据业务需求来确定责任链的形式。
- 责任链模式使用的地方很多,比如我们常见的try…catch…就是,可以有多个catch,一个个往下判断。
纯的责任链模式
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。
不纯的责任链模式
在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。
注:在实际软件系统中,很少能找到纯的责任链模式,大多数情况是不纯的责任链模式
三、模式角色和UML类图
Client(客户端):向处理者提交请求对象。
Handler(抽象处理者):定义了一个处理请求的接口,设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。持有下一个抽象处理者的引用,通过该引用,处理者可以连成一条链。
ConcreteHandler(具体处理者):抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。
代码示例1
我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器消息的级别是否属于自己的级别,如果是则相应地打印出来,否则将不打印并把消息传给下一个记录器。
#include<iostream>
using namespace std;
/* 抽象处理者 */
class AbstractLogger {
protected:
int level;
AbstractLogger *nextLogger = NULL;/* 责任链中的下一个元素 */
public:
static const int INFO = 1;
static