一、责任链设计模式概念
责任链模式(Chain Of Responsibility) 是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用场景
- 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。
- 当必须按顺序执行多个处理者时, 可以使用该模式。
- 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式
责任链设计模式的结构:
处理者 (Handler) 声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。
基础处理者 (Base Handler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。
通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。
具体处理者 (Concrete Handlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。
处理者通常是独立且不可变的, 需要通过构造函数一次性地获得所有必要地数据。
客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。
代码如下:
问题:开发一款故障报修系统,不同的业务员负责处理不同类型的故障报修,如何确保客户的维修请求能被正确处理?
解决方案:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
#include <iostream>
#include <string>
#include <list>class BaseHandler
{
private:BaseHandler* m_nextHandler;
public:BaseHandler* setNext(BaseHandler* handler){m_nextHandler = handler;return m_nextHandler;}virtual std::string handle(std::string request){if (m_nextHandler){return m_nextHandler->handle(request);}return "";}};class RobotAI :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "使用向导"){return "RobotAI:我来处理"+request+"-。\n";}else{return BaseHandler::handle(request);}}
};class TelOperator :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "常见问题"){return "TelOperator:我来处理" + request + "-。\n";}else{return BaseHandler::handle(request);}}
};class Export :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "疑难杂症"){return "Export:我来处理" + request + "-。\n";}else{return BaseHandler::handle(request);}}
};void client(BaseHandler& handler)
{std::list<std::string> requests = {"使用向导","常见问题","常见问题","疑难杂症","gahj"};for (const std::string& request : requests){std::string result = handler.handle(request);std::cout << "Client:谁来处理" << request << std::endl;if (result.empty()){std::cout << "处理结果:无法处理请求:" << request << std::endl;}else{std::cout << "处理结果:" << result << std::endl;}}
}int main()
{RobotAI robot;TelOperator tel;Export exp;robot.setNext(&tel)->setNext(&exp);std::cout << "Chain:机器人->话务员->专家" << std::endl;client(robot);return 0;
}
二、与其他模式的关系
责任链模式 (opens new window)、 命令模式 (opens new window)、 中介者模式 (opens new window)和观察者模式 (opens new window)用于处理请求发送者和接收者之间的不同连接方式:
- 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
- 命令在发送者和请求者之间建立单向连接。
- 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
- 观察者允许接收者动态地订阅或取消接收请求。
责任链 (opens new window)通常和组合模式 (opens new window)结合使用。 在这种情况下, 叶组件接收到请求后, 可以将请求沿包含全体父组件的链一直传递至对象树的底部。
责任链 (opens new window)的管理者可使用命令模式 (opens new window)实现。 在这种情况下, 你可以对由请求代表的同一个上下文对象执行许多不同的操作。
还有另外一种实现方式, 那就是请求自身就是一个命令对象。 在这种情况下, 你可以对由一系列不同上下文连接而成的链执行相同的操作。
责任链 (opens new window)和装饰模式 (opens new window)的类结构非常相似。 两者都依赖递归组合将需要执行的操作传递给一系列对象。 但是, 两者有几点重要的不同之处。
责任链 (opens new window)的管理者可以相互独立地执行一切操作, 还可以随时停止传递请求。 另一方面, 各种装饰可以在遵循基本接口的情况下扩展对象的行为。 此外, 装饰无法中断请求的传递。