以学校采购项目引出职责链模式
采购员采购教学器材
如果金额小于等于 5000,由教学主任审批
如果金额小于等于 10000,由院长审批
如果金额小于等于 30000,由副校长审批
如果金额超过 30000 以上,有校长审批
传统方式
if(x <= 5000){
教导主任处理
}else if(x > 5000 && x <= 10000){
院长处理
}else if(x > 10000 && x < 50000){
副校长处理
}else{
校长处理
}
客户端这里会使用到分支判断来对不同的采购请求处理, 这样就存在如下问题
- 如果各个级别的人员审批金额发生变化,在客户端的也需要变化
- 客户端必须明确的知道有多少个审批级别和访问
- 这样对一个采购请求进行处理和Approver (审批人) 就存在强耦合关系,不利于代码的扩展和维护
一、职责链模式
1、基本介绍
职责链模式(Chain of Responsibility Pattern),又叫责任链模式,为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦。
职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
属于行为型模式
Handler:抽象的处理者,定义了一个处理请求的接口。
ConcreteHandlerA , B :具体的处理者,处理它自己负责的请求,可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个后继者去处理,从而形成一个职责链。
Request:含有很多属性,表示一个请求。
2、代码实现
需要处理的请求类
public class SchoolRequest {
// 请求的类型
private String type;
// 请求的大概金额
private float money;
// ID
private int id;
public SchoolRequest(String type, float money, int id) {
this.type = type;
this.money = money;
this.id = id;
}
public String getType() {
return type;
}
public float getMoney() {
return money;
}
public int getId() {
return id;
}
}
审批者抽象类
//审批者
public abstract class Approver {
//聚合,下一个处理的审批者;
Approver approver;
//当前审批的部门名字
String name;
public Approver(String name) {
this.name = name;
}
//设置下一个审批者到底是谁;
public void setApprover(Approver approver) {
this.approver = approver;
}
//处理请求的方法
public abstract void HandlingRequest(SchoolRequest schoolRequest);
}
教导主任审批类
//教导主任审批
public class DirectorApprover extends Approver {
public DirectorApprover(String name) {
super(name);
}
@Override
public void HandlingRequest(SchoolRequest schoolRequest) {
if(schoolRequest.getMoney() <= 5000){
System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
System.out.println("项目ID为" + schoolRequest.getId());
}else {
approver.HandlingRequest(schoolRequest);
}
}
}
院长审批类
//院长审批
public class DeanApprover extends Approver {
public DeanApprover(String name) {
super(name);
}
@Override
public void HandlingRequest(SchoolRequest schoolRequest) {
if(schoolRequest.getMoney() <= 5000 && schoolRequest.getMoney() <= 10000){
System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
System.out.println("项目ID为" + schoolRequest.getId());
}else {
approver.HandlingRequest(schoolRequest);
}
}
}
副校长审批类
//副校长审批
public class VicePresidentApprover extends Approver {
public VicePresidentApprover(String name) {
super(name);
}
@Override
public void HandlingRequest(SchoolRequest schoolRequest) {
if(schoolRequest.getMoney() > 10000 && schoolRequest.getMoney() <= 30000){
System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
System.out.println("项目ID为" + schoolRequest.getId());
}else {
approver.HandlingRequest(schoolRequest);
}
}
}
校长审批类
//校长审批
public class PresidentApprover extends Approver {
public PresidentApprover(String name) {
super(name);
}
@Override
public void HandlingRequest(SchoolRequest schoolRequest) {
System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
System.out.println("项目ID为" + schoolRequest.getId());
}
}
测试
public class Client {
public static void main(String[] args) {
//提出请求
SchoolRequest schoolRequest = new SchoolRequest("采购教学用品", 60000, 1);
DirectorApprover directorApprover = new DirectorApprover("教导主任");
DeanApprover deanApprover = new DeanApprover("院长");
VicePresidentApprover vicePresidentApprover = new VicePresidentApprover("副校长");
PresidentApprover presidentApprover = new PresidentApprover("校长");
//设置好下一个处理的人
directorApprover.setApprover(deanApprover);
deanApprover.setApprover(vicePresidentApprover);
vicePresidentApprover.setApprover(presidentApprover);
//教导主任收到请求时
directorApprover.HandlingRequest(schoolRequest);
}
}
结果
校长能处理这个项目===>采购教学用品
项目ID为1
二、职责链模式在 SpringMVC 框架应用的源码分析
在SpringMVC中DispatcherServlet的HandlerExecutionChain也应用了这一设计模式的思路(可能并不是太典型,这个最后总结):
在doDispatch方法中定义并获取了HandlerExecutionChain的对象,然后调用了applyPreHandle、applyPostHandle方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取该请求的handler,每一个handler实为HandlerExecutionChain,它为一个处理链,负责处理整个请求
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 责任链执行预处理方法,实则是将请求交给注册的请求拦截器执行
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际的执行逻辑的部分,也就是你加了@RequestMapping注解的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 责任链执行后处理方法,实则是将请求交给注册的请求拦截器执行
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理返回的结果,触发责任链上注册的拦截器的AfterCompletion方法,其中也用到了HandlerExecutionChain注册的handler来处理错误结果
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 触发责任链上注册的拦截器的AfterCompletion方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
首先看下HandlerExecutionChain的作用:
public class HandlerExecutionChain {
private final Object handler;
private final List<HandlerInterceptor> interceptorList;
private int interceptorIndex;
}
HandlerExecutionChain持有http请求的处理器,即代码中的handler对象,以及拦截器的数组interceptors,既处理http请求的具体逻辑,又使用拦截器对http请求进行拦截,而此处对于拦截器的调用就应用了责任链模式的思路。
getHandler方法
/**
* 调用HandlerMapping处理器映射器,请求获取Handle处理器
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//如果处理器映射器集合不为空
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
//遍历处理器映射器集合
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
//调用每个处理器映射器的getHandler()方法,尝试获取处理器对象
HandlerExecutionChain handler = mapping.getHandler(request);
//如果处理器对象不为空,说明该处理器映射器获取到了正确的处理器,将其返回
if (handler != null) {
return handler;
}
}
}
return null;
}
applyPreHandler方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
return true;
}
此处遍历拦截器的数组,调用拦截器的preHandle方法对请求进行处理,并且只有当本次preHandle处理返回true时,下一个拦截器才会进行执行preHandle方法;如果返回false,就执行triggerAfterCompletion并跳出循环。
总结:为什么开头说不是特别典型的责任链模式,因为此处的拦截器没有包含对另一拦截器的引用,而是通过数组的方式来达到类似的效果。
triggerAfterCompletion方法
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var7) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
}
}
}
此处逻辑类似,只不过这里调用的是拦截器的afterCompletion方法。
applyPostHandle方法
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, mv);
}
}
此处逻辑类似,只不过这里调用的是拦截器的postHandle方法。
总结:
- 在该doDispatch方法中,使用到了HandlerExecutionChain这个类。
- HandlerExecutionChain这个类维护了一个处理器对象,和一个 HandlerInterceptor处理器拦截器的集合,可以向其中注册相应的拦截器,我们称之为拦截器执行链chain。
- HandlerExecutionChain 主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只是将请求分配给链上注册处理器执行,这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程。
参考文章:责任链模式-以SpringMVC中DispatcherServlet的HandlerExecutionChain为例_一首简单的歌-shining的博客-CSDN博客
三、职责链模式的注意事项和细节
1)将请求和处理分开,实现解耦,提高系统的灵活性
2)简化了对象,使对象不需要知道链的结构
3)性能会受到影响,特别是在链比较长的时候。因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能。
4)调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂。
应用场景
有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对 Encoding 的处理、拦截器