目录
职责链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
一个请求有多个对象可以处理,但每个对象的处理条件或权限不同,为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
概念可能不容易理解,我先举一个例子说说亲身体会的一件事,就叫小俱求实习吧。
小俱求实习
背景:2024上半年 小俱正值大三下学期
在这个92✌到处出没的社会市场下,双非一本的小俱心感没有任何优势,苦苦找实习,实习要求虽说没有秋招正式高,在苦苦投递十几大厂下,做测评、做笔试.....不知今年大厂对双非学历究竟如何评估,终于小俱迎来了美团、腾讯云智、游族的面试......每次面试后,小俱深知自己哪块还没有学到位,甚至有的问题没有听过,小俱最终进入人才池。双非就真的菜吧......小俱仍不甘心,继续沉淀......
最终小俱通过boss投递小厂,甘心为公司做牛做马,同时马不停蹄的巩固知识,通过二面,收到了北京一家实习offer,接着有重庆、成都。
++小俱满怀期待,兴致勃勃去给辅导员请假!(划重点!)++
在辅导员要求提交几种资料后
辅导员回复:++我这里只能批准3天假期++,你出去实习这件事必须和领导商量。
好,小俱等待批假......
过了一天,辅导员说:++领导说他只能批7天假++,有的课程还没有完,你这每周需要回来一次,经过我们的开会,批准不同意。
啊!小俱说那我每周请假,每周回来,辅导员仍不同意!
小俱苦苦说机会来之不易,希望领导理解通融!
辅导员其实仅仅传达了领导的命令,理智的小俱不麻烦年轻的辅导员,直接自己找领导。
于是小俱亲自找到领导:
领导:我这个只能批7 天的假,根据目前的教学管理,不允许实习,再说,你实习地点离学校远,每次请7天假也不现实,你这个就++属于请长假,你需要找大领导++,他同意就行!
小俱人不罢休,去找大领导!
大领导:根据目前的教学管理规定,大三不允许实习............(此处省略各种理由,态度好,很委婉),我们非常支持你们实习,你们有这种意识也非常好,我很支持!(.....好,说了很多,就是不给假。。。)
最终小俱实习失败。
小俱一级一级的找领导,最终失败,但小俱调整心态,继续沉淀。
现在大概理解了职责链模式了吧!
结构图
实例
结构图,举例请假、加薪场景
管理者抽象类 Manager
java
//管理者抽象类
abstract class Manager {
protected String name;
public Manager(String name) {
this.name = name;
}
//设置管理者上级
protected Manager superior;
public void setSuperior(Manager superior){
this.superior = superior;
}
//请求申请
public abstract void requsetApplications(Request request);
}
申请Request类
java
//申请
class Request{
//申请类别
private String requestType;
//申请内容
private String requestContent;
//数量
private int number;
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public void setRequestContent(String requestContent) {
this.requestContent = requestContent;
}
public void setNumber(int number) {
this.number = number;
}
public String getRequestType() {
return requestType;
}
public String getRequestContent() {
return requestContent;
}
public int getNumber() {
return number;
}
}
普通经理 CommonManager
java
//普通经理
class CommonManager extends Manager{
public CommonManager(String name) {
super(name);
}
@Override
public void requsetApplications(Request request) {
if (request.getRequestType()=="请假"&& request.getNumber()<=2){
System.out.println(this.name+":"+request.getRequestContent()+"数量:"+ request.getNumber()+"天,批准");
}else {
if (this.superior!=null){
this.superior.requsetApplications(request);
}
}
}
}
总监Director
java
//总监
class Director extends Manager{
public Director(String name) {
super(name);
}
@Override
public void requsetApplications(Request request) {
if (request.getRequestType()=="请假"&&request.getNumber()<=5){
System.out.println(this.name+":"+request.getRequestContent()+"数量:" + request.getNumber()+"天,批准");
}else {
if (this.superior!=null){
this.superior.requsetApplications(request);
}
}
}
}
总经理GeneralManager
java
//总经理 都会处理
class GeneralManager extends Manager{
public GeneralManager(String name) {
super(name);
}
@Override
public void requsetApplications(Request request) {
if (request.getRequestType()=="请假"){
System.out.println(this.name+":"+request.getRequestContent()+"数量:"+request.getNumber()+"天,批准");
}else if (request.getRequestType()=="加薪"&&request.getNumber()<=5000){
System.out.println(this.name+":"+request.getRequestContent()+"数量:"+request.getNumber()+"元,批准");
}else if (request.getRequestType()=="加薪"&&request.getNumber()>5000){
System.out.println(this.name+":"+request.getRequestContent()+"数量:"+request.getNumber()+"元,再说吧");
}
}
}
客户端:
java
class Test{
public static void main(String[] args) {
CommonManager manager = new CommonManager("经理");
Director director = new Director("总监");
GeneralManager generalManager = new GeneralManager("总经理");
//设置每个级别的上级
manager.setSuperior(director);
director.setSuperior(generalManager);
Request request = new Request();
request.setRequestType("请假");
request.setRequestContent("小菜请假");
request.setNumber(1);
manager.requsetApplications(request);
Request request2 = new Request();
request2.setRequestType("请假");
request2.setRequestContent("小菜请假");
request2.setNumber(4);
manager.requsetApplications(request2);
Request request3 = new Request();
request3.setRequestType("加薪");
request3.setRequestContent("小菜加薪");
request3.setNumber(1000);
manager.requsetApplications(request3);
Request request4 = new Request();
request4.setRequestType("加薪");
request4.setRequestContent("小菜加薪");
request4.setNumber(6000);
manager.requsetApplications(request4);
}
}
运行结果
职责链模式优点
「降低了对象之间的耦合度」
责任链模式让发送者不需要知道对方的具体是哪个处理者处理请求。
「增强了系统的可扩展性」
可以根据需要增加新的请求处理类,满足开闭原则。
「增强了给对象指派职责的灵活性」
当工作流程发生变化,客户端可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
「责任链简化了对象之间的连接」
每个对象只需保持一个指向其后继者的引用。
「责任分担」
每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成。
职责链模式缺点
- 不能保证每个请求一定被处理。由于一个「请求没有明确的接收者」,该请求可能一直传到链的末端都得不到处理。
- 当责任链比较长的时候,请求的处理可能涉及多个处理对象,系统性能受影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会造成循环调用。
使用场景
1.springmvc流程
就拿这个springMvc的执行流程来说,全部流程就组成了一个链条。每一个步骤就是一个结点,每个结点都会有对应的处理方法,每个结点处理完成之后,就会进入下一个结点。一旦某个结点出现异常,那么当前的链路就会停止,当前请求中断。
2.mybatis的执行流程
mybatis的执行流程也是通过这个责任链模式,如首先会创建这个SqlSessionFactory,然后通过这个工厂创建一个SqlSession,这个SqlSession只是一个门面模式,会通过Executer执行增删改查的操作,然后一个Handler用于设置参数,一个Handler用于返回结果集,最后通过这个StatementHandler将执行结果获取。里面的整个步骤就相当于形成了一个链条,执行完当前结点就会进入下一个结点,如果出现异常,链条终止往下执行。
3.spring的过滤器和拦截器
spring里面的这个过滤器链路的调用,以及拦截器的链路调用,也是采用这种责任链模式