责任链模式


废话不多说,直接上需求,相信工作的小伙伴一定听说过OA系统吧,这在工作生活中十分的常见。OA系统包含许多的功能,用章审批,请假调休审批,外出打卡审批、出差、报销还有采购审批等等功能……

有这样的一个需求采购审批系统需要实现以下功能:

采购员采购教学器材

  1. 如果金额 小于等于5000, 由教学主任审批 (0<=x<=5000)
  2. 如果金额 小于等于10000, 由院长审批 (5000<x<=10000)
  3. 如果金额 小于等于30000, 由副校长审批 (10000<x<=30000)
  4. 如果金额 超过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 的集合, 可以向其中注册相应的拦截器.

好了 源码分析到这里也就结束了,不知道对小可爱是否有帮助呢。

责任链模式的总结

  1. 将请求和处理分开,实现解耦,提高系统的灵活性
  2. 简化了对象,使对象不需要知道链的结构
  3. 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能
  4. 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
  5. 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器

关于责任链模式就讲到这里了。如果有帮助,欢迎点赞关注。

微信搜索【码上遇见你】获取更多精彩内容


原文始发于微信公众号(码上遇见你):责任链模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/78798.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!