设计模式--职责链模式

职责链模式

案例

编写完成学校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);
		}
		
	}
	
}

职责链模式总结
  1. 职责链模式又叫责任链模式,为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦。
  2. 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依次类推。
  3. 这种类型的设计模式属于行为型模式
  4. 简化了对象,使对象不需要知道链的结构
  5. 性能会受到影响,特别是在链比较长的时候
  6. 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂
应用场景

适合应用在有多个对象可以处理同一个请求的场景

  • 多级请求
  • 请假/加薪等审批流程
  • 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;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值