设计模式七大原则 单例模式 工厂模式 原型模式 建造者模式 适配器模式 桥接模式 装饰者模式 组合模式 外观模式 享元模式 代理模式 模板模式 命令模式 访问者模式 迭代器模式 观察者模式 中介者模式 备忘录模式 解释器模式 状态模式 策略模式
废话不多说,直接上需求,相信工作的小伙伴一定听说过OA系统吧,这在工作生活中十分的常见。OA系统包含许多的功能,用章审批,请假调休审批,外出打卡审批、出差、报销还有采购审批等等功能......
有这样的一个需求采购审批系统需要实现以下功能:
采购员采购教学器材
如果金额 小于等于5000, 由教学主任审批 (0<=x<=5000) 如果金额 小于等于10000, 由院长审批 (5000<x<=10000) 如果金额 小于等于30000, 由副校长审批 (10000<x<=30000) 如果金额 超过30000以上,有校长审批 ( 30000<x)
传统解决方案
简要说明
接收到一个采购请求后,根据采购金额来调用对应的Approver (审批 人)完成审批
传统方案解决OA系统采购审批问题分析客户端这里会使用到分支判断
(比如 switch) 来对不同的采购请求处理, 这样就存在如下问题:
如果各个级别的人员审批金额发生变化,在客户端的也需要变化 客户端必须明确的知道 有多少个审批级别和访问 对一个采购请求进行处理 和 Approver (审批人) 就存在强耦合关系,不利于代码的扩展和维护
为了解决上述问题,由此产生了本次的主题:职责链模式,也叫责任链模式(Chain of Responsibility Pattern)
职责链模式
基本概念
为请求创建了一个接收者对象的链(简单示意图)。

这种模式对请求的发送者和接收者进行解耦
职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推 这种类型的设计模式属于 行为型模式这种模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.
UML类图

简要说明
Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含另外Handler ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链 Request , 含义很多属性,表示一个请求
到这里相信大家对职责链模式应该有了一定的了解,接下来我们是用该模式解决采购审批的问题吧。
采购审批的UML类图(职责链模式)

代码演示
PurchaseRequest(请求类)
public class PurchaseRequest {
private int type = 0; //请求类型
private float price = 0.0f; //请求金额
private int id = 0;
//构造器
public PurchaseRequest(int type, float price, int id) {
this.type = type;
this.price = price;
this.id = id;
}
public int getType() {
return type;
}
public float getPrice() {
return price;
}
public int getId() {
return id;
}
}
Approver(审批人、处理人 抽象类)
public abstract class Approver {
Approver approver; //下一个处理者
String name; // 名字
public Approver(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
//下一个处理者
public void setApprover(Approver approver) {
this.approver = approver;
}
//处理审批请求的方法,得到一个请求, 处理是子类完成,因此该方法做成抽象
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
DepartmentApprover(请求类具体实现)
public class DepartmentApprover extends Approver {
public DepartmentApprover(String name) {
// TODO Auto-generated constructor stub
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
// TODO Auto-generated method stub
if(purchaseRequest.getPrice() <= 5000) {
System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
}else {
approver.processRequest(purchaseRequest);
}
}
}
CollegeApprover(请求类具体实现)
public class CollegeApprover extends Approver {
public CollegeApprover(String name) {
// TODO Auto-generated constructor stub
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
// TODO Auto-generated method stub
if(purchaseRequest.getPrice() < 5000 && purchaseRequest.getPrice() <= 10000) {
System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
}else {
approver.processRequest(purchaseRequest);
}
}
}
ViceSchoolMasterApprover(请求类具体实现)
public class ViceSchoolMasterApprover extends Approver {
public ViceSchoolMasterApprover(String name) {
// TODO Auto-generated constructor stub
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
// TODO Auto-generated method stub
if(purchaseRequest.getPrice() < 10000 && purchaseRequest.getPrice() <= 30000) {
System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
}else {
approver.processRequest(purchaseRequest);
}
}
}
SchoolMasterApprover(请求类具体实现)
public class SchoolMasterApprover extends Approver {
public SchoolMasterApprover(String name) {
// TODO Auto-generated constructor stub
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
// TODO Auto-generated method stub
if(purchaseRequest.getPrice() > 30000) {
System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
}else {
approver.processRequest(purchaseRequest);
}
}
}
Client(测试)
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建一个请求
PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000, 1);
//创建相关的审批人
DepartmentApprover departmentApprover = new DepartmentApprover("张主任");
CollegeApprover collegeApprover = new CollegeApprover("李院长");
ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("王副校");
SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("佟校长");
//需要将各个审批级别的下一个设置好 (处理人构成环形: )
departmentApprover.setApprover(collegeApprover);
collegeApprover.setApprover(viceSchoolMasterApprover);
viceSchoolMasterApprover.setApprover(schoolMasterApprover);
schoolMasterApprover.setApprover(departmentApprover);
departmentApprover.processRequest(purchaseRequest);
viceSchoolMasterApprover.processRequest(purchaseRequest);
}
}
到这里就将责任链模式的实际应用就讲完了,接下来进行熟悉的环节-源码分析
职责链模式在SpringMVC框架应用的源码分析
SpringMVC流程图(来自第三方侵权删)

SpringMVC中的HandlerExecutionChain就使用到了
源码跟踪
首先我们先跟踪一下 DispatcherServlet
源码,里面有一个核心方法doDispatch
,这里面有一个HandlerExecutionChain
它是通过mappedHandler = getHandler(processedRequest);
获取到的HandlerExecutionChain
对象。

然后我们在下面看到了这样的一个方法 applyPreHandle
方法。

然后我们继续追踪这个 applyPreHandle
方法,我们发现这个方法就是HandlerExecutionChain里面的方法,并且发现在这个方法里面拿到了一个拦截器
,调用了拦截器的preHandle
方法

此时,正好和上图springmvc的流程图所对应

图中还调用了postHandle方法,我们继续追踪......
继续回到 applyPreHandle
这个方法,如果满足条件则return回去,如果不满足条件则在下面调用了applyPostHandle
这个方法

接下来我们继续追踪到 applyPostHandle
这个方法,和applyPreHandle
方法同理,在这个方法里面拿到了一个拦截器
,调用了拦截器的postHandle
方法

还有一个 afterCompletion
方法,这个方法是在哪里进行的调用呢,其实在前面的applyPreHandle
的方法中有一个triggerAfterCompletion
方法,

然后我们点进去查看一下 triggerAfterCompletion
方法,发现在里面它也获取到了一个拦截器,然后调用了afterCompletion
方法

小结
springmvc 请求的流程图中,执行了 拦截器相关方法 interceptor.preHandler 等等 在处理SpringMvc请求时,使用到职责链模式还使用到适配器模式 HandlerExecutionChain 主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只是将请求分配给链上注册处理器执行,这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程 HandlerExecutionChain 维护了 HandlerInterceptor 的集合, 可以向其中注册相应的拦截器.
好了 源码分析到这里也就结束了,不知道对小可爱是否有帮助呢。
责任链模式的总结
将请求和处理分开,实现解耦,提高系统的灵活性 简化了对象,使对象不需要知道链的结构 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器
关于责任链模式就讲到这里了。如果有帮助,欢迎点赞关注。
微信搜索【
码上遇见你
】获取更多精彩内容
文章转载自码上遇见你,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




