目录
简述
职责链模式(也被称为责任链模式)(Chain of Responsibility),行为型设计模式之一。
什么是责职责链呢?这个链的形式更像是数据结构中的单链表,链中的每个节点都有自己的职责,同时也持有下一个节点的引用。属于自己职责范围内的请求就自行处理,并完成请求的处理;而不属于的职责就传递给下一个节点。每个节点都是如此循环,直至请求被处理或者已经没有处理节点。
这种设计模式是为了避免请求的发送者和接收者之间的耦合关系,而职责链就是中间的请求处理者,其中可能包括多个有可能处理请求的对象,并将这些对象炼成一条链。这样也使得请求发送者无需关心请求的处理细节和请求的传递。
定义
- 使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
- Client(客户端)需要设置一个职责链的各环节对象串联起来
- Handler(抽象处理者)声明一个处理请求的抽象方法,并在其中保持一个对下一个处理节点Handler对象的引用
- ConcreteHandler(具体处理角色)实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
用C++ 代码实现大话设计模式本章代码:
//请求类
class Request
{
private:
//请求的类型、内容、数量
string requestType;
string requestContent;
int m_number;
public:
void SetType(string type)
{
requestType = type;
}
std::string GetType()
{
return requestType;
}
void SetContent(string content)
{
requestContent = content;
}
std::string GetContent()
{
return requestContent;
}
void SetNumber(int number)
{
m_number = number;
}
int GetNumber()
{
return m_number;
}
};
//Handler类,声明一个处理请求的抽象方法,并在其中保持一个对下一个处理节点Handler对象的引用
class Manager
{
protected:
string m_name;
Manager *m_superior; // 管理者的上级
public:
explicit Manager(string name) :m_name(name) {}
void SetSuperior(Manager *superior)// 设置管理者的上级
{
m_superior = superior;
}
virtual void RequestApplications(Request* request) = 0; //处理请求的抽象方法
};
// 下面3个具体的处理对象
//它们都实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
class CommonManager : public Manager
{//经理
public:
explicit CommonManager(string name) : Manager(name) {}
void RequestApplications(Request* request)override
{
if ((request->GetType() == "请假") && (request->GetNumber() <= 2))
{
cout << m_name << ":" << request->GetContent() << ",数量:" << request->GetNumber() << ",被批准!" <<endl;
}
else
{
if (m_superior != nullptr)
{//让下一个继承者处理请求
m_superior->RequestApplications(request);
}
}
}
};
class Majordomo : public Manager
{//总监
public:
explicit Majordomo(string name) : Manager(name) {}
void RequestApplications(Request* request)override
{
if ((request->GetType() == "请假") && (request->GetNumber() <= 5))
{
cout << m_name << ":" << request->GetContent() << ",数量:" << request->GetNumber() << ",被批准!" << endl;
}
else
{//让下一个继承者处理请求
if (m_superior != nullptr)
{
m_superior->RequestApplications(request);
}
}
}
};
class GeneralManager : public Manager
{//总经理
public:
explicit GeneralManager(string name) : Manager(name) {}
void RequestApplications(Request* request)override
{
if (request->GetType() == "请假")
{
cout << m_name << ":" << request->GetContent() << ",数量:" << request->GetNumber() << ",被批准" << endl;
}
else if (request->GetType() == "加薪" && request->GetNumber() <= 500)
{
cout << m_name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 被批准" << endl;
}
else if (request->GetType() == "加薪" && request->GetNumber() > 500)
{
cout << m_name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 再说吧" << endl;
}
}
};
int main()
{
CommonManager jinli("金利");
Majordomo zongjian("宗剑");
GeneralManager zhongjingli("钟精励");
//设置上级,完全可以按照实际需求来进行更改
jinli.SetSuperior(&zongjian);
zongjian.SetSuperior(&zhongjingli);
//请求1:请假1天
Request request1;
request1.SetType("请假");
request1.SetContent("小菜请假");
request1.SetNumber(1);
//客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli.RequestApplications(&request1);
//请求2:请假4天
Request request2;
request2.SetType("请假");
request2.SetContent("小菜请假");
request2.SetNumber(4);
//客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli.RequestApplications(&request2);
//请求3:加薪500元
Request request3;
request3.SetType("加薪");
request3.SetContent("小菜请求加薪");
request3.SetNumber(500);
//客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli.RequestApplications(&request3);
//请求4:加薪1000元
Request request4;
request4.SetType("加薪");
request4.SetContent("小菜请求加薪");
request4.SetNumber(1000);
//客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli.RequestApplications(&request4);
system("pause");
return 0;
}
优点
- 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
注意:一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。
缺点
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 每个请求都是从链头遍历到链尾,当链很长的时候,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。一般我们可以在
Handler
中设置一个最大节点数量,在setNext
方法中判断是否已经超过最大节点数,超过则不允许继续添加处理者,避免无意识的破坏系统性能。- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
模式的应用场景
- 有许多对象可以处理用户的请求,希望程序在运行期间自动确定处理用户的那个对象。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
模式的扩展
职责链模式存在以下两种情况。
- 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
- 不纯的职责链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。
总结
责任链模式是处理请求者和处理者关系的一个非常好的设计方案。最大的优点就是将请求和处理分开。请求者可以不用知道是谁处理的,处理者也不需要知道是谁请求的,两个对象各自实现自己的功能,实现了二者耦合度的问题。
但是,责任链模式还是有他的缺点的。最大的缺点就是:如果处理者过多,就会导致这条责任链很长很长,那处理一条命令就会花费很长时间,不利于项目的运行。因此,在利用此模式的时候,需要注意处理者的数目。