工程源码:
c++设计模式-行为型模式-责任链模式https://download.csdn.net/download/qq_40788199/85697283码云:
C++设计模式-行为型模式-责任链模式https://gitee.com/gongguixing/c-design-mode.git
1、模式的定义与特点
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
注意:责任链模式也叫职责链模式。
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了。
责任链模式是一种对象行为型模式,其主要优点如下。
- 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
其主要缺点如下。
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
2、模式的结构与实现
通常情况下,可以通过数据链表来实现职责链模式的数据结构。
1. 模式的结构
职责链模式主要包含以下角色。
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。
其结构图如图 1 所示。客户端可按图 2 所示设置责任链。
3、代码实现
3.1、抽象处理者(Handler)角色
#ifndef IHANDLER_H
#define IHANDLER_H
#include <string>
#include <iostream>
using namespace std;
// 抽象处理者(Handler)角色
// 定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
class IHandler
{
public:
IHandler();
// 设置下一个处理者
void setNext(IHandler *next);
// 获取下一个处理者指针
IHandler * getNext();
// 将任务派发给下一个处理者
void nextHandle(const string &request);
// 抽象接口,处理请求的方法
virtual void handleRequest(const string &request) = 0;
private:
IHandler *mPNext;
};
#endif // IHANDLER_H
#include "ihandler.h"
IHandler::IHandler()
{
mPNext = nullptr;
}
void IHandler::setNext(IHandler *next)
{
mPNext = next;
}
IHandler *IHandler::getNext()
{
return mPNext;
}
void IHandler::nextHandle(const string &request)
{
// 若指针不为空,则说明有下一个处理者
if (mPNext)
{
mPNext->handleRequest(request);
return;
}
std::cout << "No one is handling the request, key: " << request << std::endl;
}
3.2、具体处理者(Concrete Handler)角色 1
#ifndef CONCRETEHANDLER1_H
#define CONCRETEHANDLER1_H
#include "ihandler.h"
// 具体处理者(Concrete Handler)角色
// 实现抽象处理者的处理方法,判断能否处理本次请求,
// 如果可以处理请求则处理,否则将该请求转给它的后继者。
class ConcreteHandler1 : public IHandler
{
public:
ConcreteHandler1();
//处理请求的方法
void handleRequest(const string &request) override;
};
#endif // CONCRETEHANDLER1_H
#include "concretehandler1.h"
ConcreteHandler1::ConcreteHandler1()
{
}
void ConcreteHandler1::handleRequest(const string &request)
{
// 判断是否是自己处理的请求
if (request.compare("one") == 0)
{
std::cout << "ConcreteHandler1 handle aging requests, key: " << request << std::endl;
return;
}
// 将不是自己的请求通过父类方法传递给下一个
IHandler::nextHandle(request);
}
3.3、具体处理者(Concrete Handler)角色 2
#ifndef CONCRETEHANDLER2_H
#define CONCRETEHANDLER2_H
#include "ihandler.h"
// 具体处理者(Concrete Handler)角色
// 实现抽象处理者的处理方法,判断能否处理本次请求,
// 如果可以处理请求则处理,否则将该请求转给它的后继者。
class ConcreteHandler2 : public IHandler
{
public:
ConcreteHandler2();
//处理请求的方法
void handleRequest(const string &request) override;
};
#endif // CONCRETEHANDLER2_H
#include "concretehandler2.h"
ConcreteHandler2::ConcreteHandler2()
{
}
void ConcreteHandler2::handleRequest(const string &request)
{
// 判断是否是自己处理的请求
if (request.compare("two") == 0)
{
std::cout << "ConcreteHandler2 handle aging requests, key: " << request << std::endl;
return;
}
// 将不是自己的请求通过父类方法传递给下一个
IHandler::nextHandle(request);
}
3.4、具体处理者(Concrete Handler)角色 3
#ifndef CONCRETEHANDLER3_H
#define CONCRETEHANDLER3_H
#include "ihandler.h"
// 具体处理者(Concrete Handler)角色
// 实现抽象处理者的处理方法,判断能否处理本次请求,
// 如果可以处理请求则处理,否则将该请求转给它的后继者。
class ConcreteHandler3 : public IHandler
{
public:
ConcreteHandler3();
//处理请求的方法
void handleRequest(const string &request) override;
};
#endif // CONCRETEHANDLER3_H
#include "concretehandler3.h"
ConcreteHandler3::ConcreteHandler3()
{
}
void ConcreteHandler3::handleRequest(const string &request)
{
// 判断是否是自己处理的请求
if (request.compare("three") == 0)
{
std::cout << "ConcreteHandler3 handle aging requests, key: " << request << std::endl;
return;
}
// 将不是自己的请求通过父类方法传递给下一个
IHandler::nextHandle(request);
}
3.5调用示例
#include <iostream>
#include "concretehandler1.h"
#include "concretehandler2.h"
#include "concretehandler3.h"
int main()
{
//责任链(Chain of Responsibility)模式的定义:
//为了避免请求发送者与多个请求处理者耦合在一起,
//于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;
//当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
// 实例化具体处理者
IHandler *pH1 = new ConcreteHandler1();
IHandler *pH2 = new ConcreteHandler2();
IHandler *pH3 = new ConcreteHandler3();
//组装责任链
pH1->setNext(pH2);
pH2->setNext(pH3);
// 处理请求 one
pH1->handleRequest("one");
// 处理请求 two
pH1->handleRequest("two");
// 处理请求 three
pH1->handleRequest("three");
// 处理请求 six
pH1->handleRequest("six");
return 0;
}
模式的应用场景
前边已经讲述了关于责任链模式的结构与特点,下面介绍其应用场景,责任链模式通常在以下几种情况使用。
- 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 需要在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。