【设计模式13】责任链模式,MVC的HandlerExecutionChain

责任链

职责链模式

在这里插入图片描述

1. 问题

学校OA系统的采购审批项目: 需求是

  1. 采购员采购教学器材
  2. 如果金额 小于等于5000, 由教学主任审批 (0<=x<=5000)
  3. 如果金额 小于等于10000, 由院长审批 (5000<x<=10000)
  4. 如果金额 小于等于30000, 由副校长审批 (10000<x<=30000)
  5. 如果金额 超过30000以上,有校长审批 ( 30000<x)

传统解决的问题

  1. 传统方式是:接收到一个采购请求后,根据采购金额来调用对应的Approver (审批
    人)完成审批。
  2. 传统方式的问题分析 : 客户端这里会使用到 分支判断(比如 switch) 来对不同的采
    购请求处理, 这样就存在如下问题 (1) 如果各个级别的人员审批金额发生变化,在
    客户端的也需要变化 (2) 客户端必须明确的知道 有多少个审批级别和访问
  3. 这样 对一个采购请求进行处理 和 Approver (审批人) 就存在强耦合关系,不利于代
    码的扩展和维护
  4. 解决方案 =》 职责链模式

2. 模式介绍

  1. 职责链模式(Chain of Responsibility Pattern) ,
    又叫 责任链模式,为请求创建了一个接收者
    对象的链(简单示意图)。 这种模式对请求的
    发送者和接收者进行解耦。
  2. 职责链模式通常每个接收者都包含对另一个接
    收者的引用。如果一个对象不能处理该请求,
    那么它会把相同的请求传给下一个接收者,依
    此类推。
  3. 这种类型的设计模式属于行为型模式
  • Request
    • Approver 这个不能处理,传给下一个接收者

职责链模式(Chain Of Responsibility) ,
使多个对象都有机会处理请求,从而避
免请求的发送者和接收者之间的耦合关
系。将这个对象连成一条链,并沿着这
条链传递该请求,直到有一个对象处理
它为止.

Approver

英
/əˈpruːvə(r)/
美
/əˈprʊvər/
简明 例句 百科
n.
批准者;承认者,赞成者

角色划分

  • Handler 依赖 Request 类

    • successor : Handler 自己依赖自己
    • process Request
  • Concrete Handler A 子类1,不能处理的时候,

    • 调用 父类的 Handler,使用下一个处理
  • Concrete Handler B

  • Client 创建 Request,放入 Handler

  1. Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外Handler
  2. ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处
    理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
  3. Request , 含义很多属性,表示一个请求
  • Client 生成 Purchase Request (类)
    • 传递给 Approver ,就是 上面的 Handler
  • Approver
    • Department Approver
    • College Approver
    • Vice School Master Approver
    • School Master Approver 如果不能处理,就找 系主任
purchase
英
/ˈpɜːtʃəs/
美
/ˈpɜːrtʃəs/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
<正式>购买,采购;<正式>购买的东西;<法律>(非继承性的)财产置得;<正式>紧握,牢牢抓住;(移动重物的)滑轮(或类似装置)
v.
<正式> 购买,采购;<古>(努力或艰难地)获得,得到;(航海)(用滑轮或杠杆)升起,举起(绳,索,锚)

3. 使用模式

请求对象

//请求类
public class PurchaseRequest {

	private int type = 0; //请求类型
	private float price = 0.0f; //请求金额
	private int id = 0;
	//构造器 和 Get
}

顶层接口

public abstract class Approver {

	Approver approver;  //下一个处理者
	String name; // 名字
	
    //构造,name赋值

	//下一个处理者
	//setApprover
	
	//处理审批请求的方法,得到一个请求, 处理是子类完成,因此该方法做成抽象
	public abstract void processRequest(PurchaseRequest purchaseRequest);
}
其子类
//系主任
public class DepartmentApprover extends Approver {

	public DepartmentApprover(String name) {
		super(name);
	}

	@Override
	public void processRequest(PurchaseRequest purchaseRequest) {
		if(purchaseRequest.getPrice() <= 5000) {
			System.out.println(" 请求编号 id= " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
		}else {
			approver.processRequest(purchaseRequest);
		}
	}
    
}
CollegeApprover //院长
if(purchaseRequest.getPrice() < 5000 && purchaseRequest.getPrice() <= 10000) {}

ViceSchoolMasterApprover //副校长
if(purchaseRequest.getPrice() < 10000 && purchaseRequest.getPrice() <= 30000) {}
    
SchoolMasterApprover //校长
if(purchaseRequest.getPrice() > 30000) {}
vice
n.
堕落,邪恶;小毛病,坏习惯;(与性或毒品有关的)罪行,道德败坏行为;老虎钳(同 vise);<非正式>代理人,任副职者;(尤指马厩里马因厌倦而出现的)劣性,恶癖
v.
握住,钳紧
adj.
副的;代替的,代理的

进行测试

		//创建一个请求
		PurchaseRequest request = new PurchaseRequest(1, 31000, 1);
		
		//创建相关的审批人
		DepartmentApprover department = new DepartmentApprover("张主任");
		CollegeApprover college = new CollegeApprover("李院长");
		ViceSchoolMasterApprover viceSchoolMaster = new ViceSchoolMasterApprover("王副校");
		SchoolMasterApprover schoolMaster = new SchoolMasterApprover("佟校长");
	
		//需要将各个审批级别的下一个设置好 (处理人构成环形: )
		department.setApprover(college);
		college.setApprover(viceSchoolMaster);
		viceSchoolMaster.setApprover(schoolMaster);
		schoolMaster.setApprover(department);
		
		department.processRequest(request);
		viceSchoolMaster.processRequest(request);
 请求编号 id= 1 被 佟校长 处理
 请求编号 id= 1 被 佟校长 处理

SpringMVC

  1. SpringMVC-HandlerExecutionChain 类就使用到职责链模式
  2. SpringMVC请求流程简图
  1. Request
  2. Dispatcher Servlet
    1. 遍历 Handler Mapping 集合
      1. 找 Handler Method。
      2. 是一个 封装了 Method 以及 Parameter 的 helper class
      3. 在 Handler Mapping 中 被构造,
      4. 并在 Handler Adapter 中 被使用。
    2. 找到对应的 Handler Mapping,并 得到 Handler Execution Chain ,其内部包含了 拦截器
      1. Handler Interceptor 拦截 ,调用 pre Handler方法 前置方法
    3. 使用 Handler Execution Chain 的 handler
      1. 遍历 Handler Adapter 集合
      2. 找到 支持 此 Handler的 Handler Adapter
    4. 使用 Handler Adapter 得到 Model And View
      1. Handler Interceptor拦截 调用 post handle 方法 后置方法
      2. 响应之前,最后一步,还会调用 after Completion方法
    5. 异常处理。前面 4个 步骤,可能会 发生异常。
      1. 使用 Handler Excepton Resolver 策略 解决。

DispatcherServlet

public class DispatcherServlet extends FrameworkServlet {
    //doDispatcher方法
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HandlerExecutionChain mappedHandler = null; 
    
    mappedHandler = getHandler(processedRequest);//获取到HandlerExecutionChain对象
    
    //在 mappedHandler.applyPreHandle 内部 得到啦 HandlerInterceptor interceptor
    //调用了拦截器的  interceptor.preHandle
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
		return;
	}
    
    //说明:mappedHandler.applyPostHandle 方法内部获取到拦截器,并调用 
	//拦截器的  interceptor.postHandle(request, response, this.handler, mv);
	mappedHandler.applyPostHandle(processedRequest, response, mv);
    
    //说明:在  mappedHandler.applyPreHandle内部中,
	//还调用了  triggerAfterCompletion 方法,该方法中调用了  
	HandlerInterceptor interceptor = getInterceptors()[i];
    
    try {
        interceptor.afterCompletion(request, response, this.handler, ex);
    }
    catch (Throwable ex2) {
        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    }
}

HandlerExecutionChain

public class HandlerExecutionChain {

	// applyPreHandle 方法
    // 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)) {
             //这里 调用了:
            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);
		}
	}
	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);
			}
			catch (Throwable ex2) {
				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
			}
		}
	}

- springmvc 请求的流程图中,执行了 拦截器相关方法 interceptor.preHandler 等等
- 在处理SpringMvc请求时,使用到职责链模式还使用到适配器模式
- HandlerExecutionChain 主要负责的是请求拦截器的执行和请求处理,但是他本身不
处理请求,只是将请求分配给链上注册处理器执行, 这是职责链实现方式,减少职责
链本身与处理逻辑之间的耦合,规范了处理流程
- HandlerExecutionChain 维护了 HandlerInterceptor 的集合, 可以向其中注册相应
的拦截器

  • 适配器
    • Handler Adapter
    • Request Mapping Handler Adapter

注意事项

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值