职责链模式
职责链模式
OA系统的采购审批项目
学校 OA 系统的采购审批项目,需求是
- 采购员采购教学器材
- 如果金额小于等于 5000,由教学主任审批(0 < x ≤ 5000)
- 如果金额小于等于 10000,由院长审批(5000 < x ≤ 10000)
- 如果金额小于等于 30000,由副校长审批(10000< x ≤ 30000)
- 如果金额超过 30000 以上,有校长审批(30000 < x)
请设计程序完成采购审批项目
传统方案解决 OA 系统审批
传统方案解决 OA 系统审批问题分析
传统方式是:接收到一个采购请求后,根据采购金额来调用对应的
Approver
(审批人)完成审批传统方式的问题分析:客户端这里会使用到分支判断(比如
switch
)来对不同的采购请求处理,这样就存在如下问题如果各个级别的人员审批金额发生变化,在客户端的也需要变化
客户端必须明确的知道有多少个审批级别和访问
这样对一个采购请求进行处理和
Approver
(审批人)就存在强耦合关系,不利于代码的扩展和维护解决方案 =》职责链模式
职责链模式
基本介绍
- 职责链模式(Chain of Responsibility Pattern),又叫责任链模式:为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦
- 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推
- 这种类型的设计模式属于行为型模式
uml类图
职责链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系
将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
Handler
抽象处理者:定义了一个处理请求的方法,同时含有另外一个Handler
ConcreteHandler
具体处理者:处理自己负责的请求,同时可以访问它的后继者(即下一个处理者) ;如果可以处理请求,则进行处理,否则交给后继者去处理,从而形成一个职责链Request
含有很多属性,表示一个请求
职责链模式解决 OA 系统采购审批项目
uml类图
核心代码
//采购申请类
public class PurchaseRequest {
private Integer id;
private Float price;
public PurchaseRequest(Integer id, Float price) {
this.id = id;
this.price = price;
}
public Integer getId() {
return id;
}
public Float getPrice() {
return price;
}
}
//抽象审批人对象
public abstract class Approver {
protected Approver nextApprover;
protected String name;
public Approver(String name) {
this.name = name;
}
/**
* 设置后继者
*
* @param nextApprover
*/
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
/**
* 处理请求的方法
*/
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
具体审批人对象
//副校长审批人
public class ChancellorApprover extends Approver {
public ChancellorApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 30000) {
System.out.println("请求编号:" + purchaseRequest.getId() + ",处理人:" + this.name);
} else {
nextApprover.processRequest(purchaseRequest);
}
}
}
//院长审批人
public class DepartmentHeadApprover extends Approver {
public DepartmentHeadApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
System.out.println("请求编号:" + purchaseRequest.getId() + ",处理人:" + this.name);
} else {
nextApprover.processRequest(purchaseRequest);
}
}
}
//教学主任审批人
public class TeachDirectorApprover extends Approver {
public TeachDirectorApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() <= 5000) {
System.out.println("请求编号:" + purchaseRequest.getId() + ",处理人:" + this.name);
} else {
nextApprover.processRequest(purchaseRequest);
}
}
}
//副校长审批人
public class ViceChancellorApprover extends Approver {
public ViceChancellorApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <= 30000) {
System.out.println("请求编号:" + purchaseRequest.getId() + ",处理人:" + this.name);
} else {
nextApprover.processRequest(purchaseRequest);
}
}
}
测试
public class Client {
public static void main(String[] args) {
//创建一个请求
PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000.0f);
//创建相关的审批人
TeachDirectorApprover teachDirectorApprover = new TeachDirectorApprover("童主任");
DepartmentHeadApprover departmentHeadApprover = new DepartmentHeadApprover("王院长");
ViceChancellorApprover viceChancellorApprover = new ViceChancellorApprover("钱副校长");
ChancellorApprover chancellorApprover = new ChancellorApprover("郑校长");
//设置后继者(处理人形成环形)
teachDirectorApprover.setNextApprover(departmentHeadApprover);
departmentHeadApprover.setNextApprover(viceChancellorApprover);
viceChancellorApprover.setNextApprover(chancellorApprover);
chancellorApprover.setNextApprover(teachDirectorApprover);
//发起一个请求 童主任发起请求,直到郑校长执行
teachDirectorApprover.processRequest(purchaseRequest); //请求编号:1,处理人:郑校长
}
}
职责链模式在 SpringMVC 框架应用
首先,当用户会发起一个request
请求到后台,这个request
请求首先会经过DispatcherServlet
,DispatcherServlet
对象首先会遍历接收到的HandlerMapping
集合,然后再找到对应的HandlerMapping
集合,并得到HandlerExecutionChain
对象。这个HandlerExecutionChain
对象内部包含了一些拦截器。拿到HandlerInterceptor
拦截器过后,有以下几个操作
首先会调用
HandlerInterceptor
中的preHandle()
方法然后会调用
HandlerInterceptor
中的postHandle()
方法最后会调用
HandlerInterceptor
中的afterCompletion()
方法
在DispatcherServlet
中找到doDispatch()
方法,发现该方法中定义了一个HandlerExecutionChain
对象
在后续的代码逻辑中,调用了getHandler()
方法,接收一个processedRequest
请求对象作为参数,得到初始化的HandlerExecutionChain
对象
直接对mappedHandler
对象进行高亮,查找相关调用逻辑。找到如下几处代码逻辑。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mappedHandler.applyPostHandle(processedRequest, response, mv);
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
首先会执行mappedHandler
的applyPreHandle()
方法:如果返回为false
,则判断成立,后续代码不再执行;否则继续往下执行,调用mappedHandler
的applyPostHandle()
方法
再看看内部逻辑
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {//调用了preHandle
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);//调用了postHandle
}
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);//最后调用afterCompletion方法
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
通过对上述SpringMVC
的源码分析,这里进行简单的梳理总结
SpringMVC
请求的流程图中,执行了拦截器相关方法,如interceptor.preHandler()
在处理
SpringMVC
请求时,使用到职责链模式和适配器模式HandlerExecutionChain
:主要负责请求拦截器的执行和请求处理,但是本身不处理请求,只是将请求分配给 链上注册处理器 执行。这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程HandlerExecutionChain
:维护了Handlerlnterceptor
的集合,可以向其中注册相应的拦截器
小结
- 将请求和处理分开,实现解耦,提高系统的灵活性
- 简化了对象,使对象不需要知道链的结构
- 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在
Handler
中设置一个最大节点数量,在setNext()
方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能 - 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
- 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假 / 加薪等审批流程、Java Web 中 Tomcat 对
Encoding
的处理、拦截器