文章目录
- 什么是责任链模式?
- 详细示例
- SpingMVC 中的责任链模式使用
- 总结
什么是责任链模式?
在我们日常生活中,经常会出现一种场景:一个请求需要经过多个对象的处理才能得到最终的结果。比如,一个请假申请,需要经过组长、部门经理、总经理等多个级别的审批。这种场景下,使用责任链模式是一种非常优雅的解决方案。
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它的主要目的是将请求的发送者和接收者解耦,使得多个对象都有机会处理这个请求。这种模式通过将请求沿着处理者链进行传递,直到有一个对象处理它为止。
在责任链模式中,主要涉及以下三个角色:
- 抽象处理者(Handler):处理器抽象接口,定义了处理请求的方法和执行下一步处理的处理器。
- 具体处理者(ConcreteHandler):实现抽象处理者接口,具体处理请求的逻辑在这里实现。如果不能处理当前请求,则将请求传递给下一个处理者。
- 客户端(Client):负责创建并组装责任链,将请求发送给链中的第一个处理者。
代码:
// 抽象处理器
public abstract class Handler {
private Handler next;
public Handler getNext() {
return next;
}
public void setNext(Handler next) {
this.next = next;
}
public abstract void handle(Object request);
}
// 具体处理器 1
public class ConcreteHandler1 extends Handler {
@Override
public void handle(Object request) {
System.out.println("concrete handler 1 execute request. request: " + request);
if (getNext() != null) {
getNext().handle(request);
}
}
}
// 具体处理器 2
public class ConcreteHandler2 extends Handler {
@Override
public void handle(Object request) {
System.out.println("concrete handler 2 execute request. request: " + request);
if (getNext() != null){
getNext().handle(request);
}
}
}
// 具体处理器 3
public class ConcreteHandler3 extends Handler {
@Override
public void handle(Object request) {
System.out.println("concrete handler 3 execute request. request: " + request);
if (getNext() != null) {
getNext().handle(request);
}
}
}
public static void main(String[] args) {
Handler concreteHandler1 = new ConcreteHandler1();
Handler concreteHandler2 = new ConcreteHandler2();
Handler concreteHandler3 = new ConcreteHandler3();
concreteHandler1.setNext(concreteHandler2);
concreteHandler2.setNext(concreteHandler3);
concreteHandler1.handle("my request.");
}
从上面的代码我们可以看到其实责任链模式是非常简单的,但是其中有几个点需要注意一下:
- 首先我们需要对整个责任链进行初始化,即设置每个处理器的 next。
- 在每个具体处理器处理完之后需要手动调用下一个处理器的 handle 方法来执行下一步处理,这里其实还可以使用模板方法模式进行优化。
控制台输出如下:
concrete handler 1 execute request. request: my request.
concrete handler 2 execute request. request: my request.
concrete handler 3 execute request. request: my request.
详细示例
以日常请假为例。请假申请会先到你的直属 leader 处审批,审批通过后再到部门 leader 处审批,部门 leader 通过后,最后到人事处报备记录请假天数。
如果在传统企业里面,我们需要手写一份请假表,然后跑到直属 leader 办公室,让直属 leader 签字,然后再到部门 leader 办公室签字,最后还要跑到人事处上交请假单,这样相当于发出了三次请求,才能走完整个请假流程。
但是当我们使用责任链模式后整个请假流程就变的简单了,我们只需要发起一次请假请求,接下来你的请假请求便会自动的在审批人中间进行流转,这个时候我们的责任链模式便派上用场。
代码如下:
// 请假抽象处理器
public abstract class DayOffHandler {
private DayOffHandler next;
public DayOffHandler getNext() {
return next;
}
public void setNext(DayOffHandler next) {
this.next = next;
}
public abstract void handle(String request);
}
// 直属 leader 处理
public class GroupLeaderHandler extends DayOffHandler {
@Override
public void handle(String request) {
System.out.println("直属 leader 审查: " + request);
System.out.println("同意请求");
if (getNext() != null) {
getNext().handle(request);
}
}
}
// 部门 leader 处理
public class DepartmentLeaderHandler extends DayOffHandler{
@Override
public void handle(String request) {
System.out.println("部门 leader 审查: " + request);
System.out.println("同意请求");
if (getNext() != null) {
getNext().handle(request);
}
}
}
// 人事处处理
public class HRHandler extends DayOffHandler {
@Override
public void handle(String request) {
System.out.println("人事处审查: " + request);
System.out.println("同意请求,记录请假");
if (getNext() != null) {
getNext().handle(request);
}
}
}
客户端:
public static void main(String[] args) {
DayOffHandler groupLeaderHandler = new GroupLeaderHandler();
DayOffHandler departmentLeaderHandler = new DepartmentLeaderHandler();
DayOffHandler hrHandler = new HRHandler();
groupLeaderHandler.setNext(departmentLeaderHandler);
departmentLeaderHandler.setNext(hrHandler);
System.out.println("收到面试通知,需要请假");
String request = "家中有事,请假半天,望批准";
System.out.println("发起请求:");
groupLeaderHandler.handle(request);
}
上面的代码定义了请假抽象处理类和三个具体的处理人,我们需要将这三个处理人的流程初始化串联起来,并且一步步的执行下去
结果:
收到面试通知,需要请假
发起请求:
直属 leader 审查: 家中有事,请假半天,望批准
同意请求
部门 leader 审查: 家中有事,请假半天,望批准
同意请求
人事处审查: 家中有事,请假半天,望批准
同意请求,记录请假
SpingMVC 中的责任链模式使用
在 SpringMVC 中的 Interceptor 用到了责任链模式。首先来看看 Interceptor 的抽象处理类;
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
在抽象处理类中,定义了三个方法,分别是处理前置处理器、后置处理器和整个流程完成之后的处理。通过 HandlerExecutionChain
将拦截器串联起来,在 HandlerExecutionChain
中,我们需要关注 applyPreHandle
、applyPostHandle
和 triggerAfterCompletion
三个方法,这三个方法分别执行了拦截器中所定义的 preHandle
、postHandle
和 afterCompletion
方法。并且从代码中也能够看处,和前面的过滤器一样,所有的拦截器都存放在 interceptors
数组中,并在三个方法中遍历 interceptors
数组依次执行相应的方法
public class HandlerExecutionChain {
@Nullable
private HandlerInterceptor[] interceptors;
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
}
总结
责任链模式是常见的设计模式,各个不同职责的处理器串联起来,通过一次请求便能够执行完每个处理器的处理方法。
通过这样的方式请求的发送者只需发出一次请求同时也不需要知道详细的链路结构;而请求的接送方只关心自己的处理逻辑,自己处理完成之后将请求传递给下一个接收者,从而完成自己的任务,这样便实现了请求发送者和接收者的解耦。