职责链模式
案例
编写完成学校OA系统的采购审批项目:
- 采购金额小于等于500,由教学主任审批
- 采购金额小于等于2000,由院长审批
- 采购金额小于等于5000,由副校长审批
- 采购金额大于5000,由校长审批
传统解决方案
在采购请求处理类中用if else判断由哪一个处理人来处理
class OldRequest{
int id;
OldRequest(){
this.id = (new Random()).nextInt();
}
void process(float money){
if(money > 0 && money <= 500) {
//教学主任处理
}else if(money < 2000) {
//院长处理
}else if(money < 5000) {
//副校长处理
}else{
//校长处理
}
}
}
public static void main(String[] args){
new OldRequest().process(1000);
}
传统解决方案带来的问题
客户端(请求者)这里会使用到分支判断来处理不同的采购请求金额,这样就存在如下问题:1.如果处理逻辑发生变化,比如各个级别的人员审批金额发生变化,那么客户端也得进行修改,违反了ocp原则。2.客户端必须知道有多少个审批级别和访问。
从以上可以看出,该方案的客户端和处理逻辑存在紧密的耦合,不利于扩展和维护。
用职责链模式解决问题
三个角色:使用者(Client),请求者(Request),处理者(Handler)以及它的子类
Handler:定义了处理请求的接口方法process,并且其聚合了一个Handler,存储下一个处理者的引用。当当前处理者不能处理请求时,就将该请求委派给下一个处理者处理,依此类推,往这条“处理者链”一直委派下去,直到找到可以处理该请求的处理者,若最终没有找到,则报错。
这样既使多个处理者都有机会处理请求,也能避免请求的发送者和接收者之间的耦合关系。
现在如果我们想要改变各个级别的人员审批金额,只需要修改相关处理者就行,客户端代码不需要改动,遵守了ocp原则。
/**
*
* @ClassName ResponseChainPattern
* @Description 职责链模式演示
* @author fuling
* @date 2020年11月2日 上午11:43:41
*/
public class ResponseChainPattern {
public static void main(String[] args) {
//创建一个请求
Request request = new Request(2000);
//创建四个处理者
Handler handler1 = new DepartmentHandler();
Handler handler2 = new CollegeHandler();
Handler handler3 = new ViceSchoolMasterHandler();
Handler handler4 = new SchoolMasterHandler();
//将四个处理者链成一个环
handler1.setHandler(handler2);
handler2.setHandler(handler3);
handler3.setHandler(handler4);
handler4.setHandler(handler1);
//将请求交给第一个处理者,开始“走链”
handler1.process(request);
}
}
/**
*
* @ClassName Request
* @Description 请求者
* @author fuling
* @date 2020年11月2日 上午11:50:38
*/
class Request{
int id;
float money;
Request(float money){
this.id = (new Random()).nextInt();
this.money = money;
}
}
/**
*
* @ClassName Handler
* @Description 处理者的抽象类定义
* @author fuling
* @date 2020年11月2日 上午11:49:22
*/
abstract class Handler{
//关键点1!
Handler handler;
Handler(){}
Handler(Handler handler){
this.handler = handler;
}
void setHandler(Handler handler) {
this.handler = handler;
}
//关键点2!
public abstract void process(Request request);
}
/**
*
* @ClassName DepartmentHandler
* @Description 教学主任
* @author fuling
* @date 2020年11月2日 下午1:59:34
*/
class DepartmentHandler extends Handler{
DepartmentHandler(){}
DepartmentHandler(Handler handler){
super(handler);
}
@Override
public void process(Request request) {
if(request.money > 0 && request.money <= 500) {
System.out.println("第一个处理器处理了编号为" + request.id + "的请求");
}else {
this.handler.process(request);
}
}
}
/**
*
* @ClassName CollegeHandler
* @Description 院长
* @author fuling
* @date 2020年11月2日 下午1:59:34
*/
class CollegeHandler extends Handler{
CollegeHandler(){}
CollegeHandler(Handler handler){
super(handler);
}
@Override
public void process(Request request) {
if(request.money > 500 && request.money <= 2000) {
System.out.println("第二个处理器处理了编号为" + request.id + "的请求");
}else {
this.handler.process(request);
}
}
}
/**
*
* @ClassName ViceSchoolMasterHandler
* @Description 副校长
* @author fuling
* @date 2020年11月2日 下午1:59:34
*/
class ViceSchoolMasterHandler extends Handler{
ViceSchoolMasterHandler(){}
ViceSchoolMasterHandler(Handler handler){
super(handler);
}
@Override
public void process(Request request) {
if(request.money > 2000 && request.money <= 5000) {
System.out.println("第三个处理器处理了编号为" + request.id + "的请求");
}else {
this.handler.process(request);
}
}
}
/**
*
* @ClassName SchoolMasterHandler
* @Description 校长
* @author fuling
* @date 2020年11月2日 下午1:59:34
*/
class SchoolMasterHandler extends Handler{
SchoolMasterHandler(){}
SchoolMasterHandler(Handler handler){
super(handler);
}
@Override
public void process(Request request) {
if(request.money > 5000) {
System.out.println("第四个处理器处理了编号为" + request.id + "的请求");
}else {
this.handler.process(request);
}
}
}
职责链模式总结
- 职责链模式又叫责任链模式,为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦。
- 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依次类推。
- 这种类型的设计模式属于行为型模式
- 简化了对象,使对象不需要知道链的结构
- 性能会受到影响,特别是在链比较长的时候
- 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂
应用场景
适合应用在有多个对象可以处理同一个请求的场景
- 多级请求
- 请假/加薪等审批流程
- Java web中Tomcat对Encoding的处理
- 拦截器
- spring mvc中的HandlerExecutionChain类
在spring框架中的应用
spring mvc拦截到请求后会将请求传递给拦截器链处理
DispatcherServlet中的doDispatch方法
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);
// 获取处理链
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用处理链中的拦截器链来处理请求
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
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) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
HandlerExecutionChain 中的applyPreHandle方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取所有注册的拦截器
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//循环调用拦截器链上的节点来处理
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//如果当前拦截器将请求全部处理完毕,则停止拦截器链的调用
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}