一文带你读懂设计模式之责任链模式

这篇具有很好参考价值的文章主要介绍了一文带你读懂设计模式之责任链模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.前言

emm,翻了一下之前刚入职时候的学习笔记,发现之前在熟悉业务代码的时候曾经专门学习并整理过过设计模式中的责任链模式,之前只是对其简单了解过常用的设计模式有哪些,并未结合实例和源码深入对其探究,利用熟悉代码契机进行系统学习并整理文档如下。

2.什么是责任链模式?

俗话说没有规矩不成方圆,我们无论在工作还是生活中很多事情都需要按照规定的流程办事,这样的流程往往都是环环相扣的,上一部完成之后才会流转到下一步执行。比如我们在做饭时都是先买菜、洗菜、切菜、炒菜、装盘在这样的过程中只有上一步完成之后才能开始下一步最后得到一道做好的菜;又比如在晋升提名时,首先我们要做一个述职报告进行述职,然后就是评审小组打分,评审小组筛选通过后,流转到项目组领导处审批,项目组领导根据述职报告和评审小组分数决定是否晋升,项目组领导同意之后最后流转到部门领导审批并给出最后结果。像这种一步一步完成流程都可以通过责任链模式来实现。

  • 简介: 责任链模式顾名思义是将不同职责的步骤串联起来执行,并且一个步骤执行完成之后才能够执行下一个步骤。从名字可以看出通常责任链模式使用链表来完成。因此当执行任务的请求发起时,从责任链上第一步开始往下传递,直到最后一个步骤完成。在责任链模式当中,客户端只用执行一次流程开始的请求便不再需要参与到流程执行当中,责任链上的流程便能够自己一直往下执行,客户端同样也并不关心执行流程细节,从而实现与流程之间的解耦。
  • 模式结构:责任链模式主要角色如下:

抽象处理器(Handler):处理器抽象接口,定义了处理请求的方法和执行下一步处理的处理器。

具体处理器(ConcreteHandler):执行请求的具体实现,先根据请求执行处理逻辑,完成之后将请求交给下一个处理器执行。

调用者:调用者通过创建处理器并将请求交给处理器进行处理。

  • 相关代码:
// 抽象处理器
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.



3.具体实例demo

日常请假为例。请假申请会先到你的直属 leader 处审批,审批通过后再到部门 leader 处审批,部门 leader 通过后,最后到人事处报备记录请假天数。如果在传统企业里面,我们需要手写一份请假表,然后跑到直属 leader 办公室,让直属 leader 签字,然后再到部门 leader 办公室签字,最后还要跑到人事处上交请假单,这样相当于发出了三次请求,才能走完整个请假流程。

但是在现代各种 OA 系统管理下,整个请假流程就变的简单了,我们只需要发起一次请假请求,接下来你的请假请求便会自动的在审批人中间进行流转,这个时候我们的责任链模式便派上用场。代码如下:

// 请假抽象处理器
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);
}



客户端代码中可以看到,我们首先实例化了三个具体处理人,然后通过 setNext 方法将他们串联起来,而我们只需向直属 leader 发起一次请假请求即可,整个审批流程便能够自动的执行下去,不需要再挨个跑办公室申请了。执行后的结果如下:

收到面试通知,需要请假
发起请求:
直属 leader 审查: 家中有事,请假半天,望批准
同意请求
部门 leader 审查: 家中有事,请假半天,望批准
同意请求
人事处审查: 家中有事,请假半天,望批准
同意请求,记录请假



4.责任链模式在源码中的应用

说到责任链模式,那么最著名的当然是 Servlet 中的过滤器 Filter 了,在这拦截器和过滤器的体系中都使用责任链模式来依次处理每个请求,首先看看过滤器 Filter 的使用方式。Filter 接口如下:

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}


  • FilterChain 便是过滤器 Filter 的一条责任链,其代码如下:
public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}


public final class ApplicationFilterChain implements FilterChain {
    
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (Globals.IS_SECURITY_ENABLED) {
            final ServletRequest req = request;
            final ServletResponse res = response;

            try {
                AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                    public Void run() throws ServletException, IOException {
                        ApplicationFilterChain.this.internalDoFilter(req, res);
                        return null;
                    }
                });
            } catch (PrivilegedActionException var7) {
                Exception e = var7.getException();
                if (e instanceof ServletException) {
                    throw (ServletException)e;
                }

                if (e instanceof IOException) {
                    throw (IOException)e;
                }

                if (e instanceof RuntimeException) {
                    throw (RuntimeException)e;
                }

                throw new ServletException(e.getMessage(), e);
            }
        } else {
            this.internalDoFilter(request, response);
        }

    }

    private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.pos < this.n) {
            ApplicationFilterConfig filterConfig = this.filters[this.pos++];

            try {
                Filter filter = filterConfig.getFilter();
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
                }

                if (Globals.IS_SECURITY_ENABLED) {
                    Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                    Object[] args = new Object[]{request, response, this};
                    SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
                } else {
                    filter.doFilter(request, response, this);
                }

            } catch (ServletException | RuntimeException | IOException var15) {
                throw var15;
            } catch (Throwable var16) {
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.filter"), e);
            }
        } else {
            try {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }

                if (request.isAsyncSupported() && !this.servletSupportsAsync) {
                    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
                }

                if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
                    Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                    Object[] args = new Object[]{request, response};
                    SecurityUtil.doAsPrivilege("service", this.servlet, classTypeUsedInService, args, principal);
                } else {
                    this.servlet.service(request, response);
                }
            } catch (ServletException | RuntimeException | IOException var17) {
                throw var17;
            } catch (Throwable var18) {
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var18);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set((Object)null);
                    lastServicedResponse.set((Object)null);
                }

            }

        }
    }
}



  • internalDoFilter() 方法中,可以看到整个 FilterChain 上使用数组 filters 存放每一个过滤器及其配置并使用 pos 记录当前遍历到哪一个过滤器,然后再执行获取到的 FilterdoFilter 方法。与前面所讲链表方式存放不同,这里的链路使用数组来进行存放。

  • spring中的责任链模式

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 中,我们需要关注 applyPreHandleapplyPostHandletriggerAfterCompletion 三个方法,这三个方法分别执行了拦截器中所定义的 preHandlepostHandleafterCompletion 方法。并且从代码中也能够看处,和前面的过滤器一样,所有的拦截器都存放在 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);
                }
            }
        }

    }
}



5.总结

责任链模式也是常见的设计模式,各个不同职责的处理器串联起来,通过一次请求便能够执行完每个处理器的处理方法。通过这样的方式请求的发送者只需发出一次请求同时也不需要知道详细的链路结构;而请求的接送方只关心自己的处理逻辑,自己处理完成之后将请求传递给下一个接收者,从而完成自己的任务,这样便实现了请求发送者和接收者的解耦。而从源码分析中可以看到,责任链模式虽然常见使用链表结构,但是使用数组和列表同样能够完成需求。

作者:京东科技 宋慧超

来源:京东云开发者社区文章来源地址https://www.toymoban.com/news/detail-655653.html

到了这里,关于一文带你读懂设计模式之责任链模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 抖音小店无货源处罚全解,一文带你读懂官方规则,合理规避风险

    大家好,我是电商年年 根据官方解释, “无货源店铺” ,指店铺经营者没有现货,在网上找产品找货源,在未取得货源方授权的情况下,把货源信息“搬运”到自己的店铺中,等有消费者下单,店铺经营者再去 货源方店铺下 单,由货源方向消费者派单发货。   那官方对于

    2024年02月03日
    浏览(63)
  • 一口气带你读懂跨境电商出海模式

    作为一名跨境电商卖家,掌握正确的“出海模式”至关重要。今天,就让我们一起揭开跨境电商的神秘面纱,探索它的各种出海模式,为你的电商之旅提供指引。 1️⃣ 国际站模式 ✅起步门槛:10W及以内 ✅利润:高 ✅客单价:较高(以 B2B 大单为主) ✅运营难度:中低,

    2024年02月21日
    浏览(50)
  • Linux - 一篇带你读懂 Curl Proxy 代理模式

    curl 是一个很有名的处理网络请求的 类Unix 工具。出于某种原因,我们进行网络请求,需要设置代理。本文讲全面介绍如何为 curl 设置代理 设置代理参数 基本用法 设置 HTTP 代理 下面两种设置代理的方式是可以的 由于代理地址的默认协议为  HTTP, 所以可以省略,按照下面的

    2024年02月05日
    浏览(65)
  • 一文带你通俗理解23种软件设计模式(推荐收藏,适合小白学习,附带C++例程完整源码)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处        设计模式是为了解决在软件开发过程中遇到的某些问题而形成的思想。同一场景有多种设计模式可以应用,不同的模式有各自的优缺点,开发者可以基于自身需求

    2024年02月09日
    浏览(53)
  • 设计模式—责任链模式

    一、待解决问题 : 减少代码中 if else 语句,降低代码圈复杂度或深度,增强可读性。 1、需求背景: 采购订单创建,需要验证采购员、物料、供应商、供应商的银行账号等信息。如采购员权限到期、或供应商失效等问题,都无法下单。 2、代码如下: 学习使用责任链模式后

    2024年02月10日
    浏览(43)
  • 《设计模式》责任链模式

    定义 : 责任链模式将链中每一个节点都看成一个对象,并且将这些节点对象连成一条链,请求会沿着这条链进行传递,直到有对象处理它为止,这使得多个对象都有机会接收请求,避免了请求发送者和接收者之间的耦合。 属于 行为型 设计模式。 责任链模式的角色组成 :

    2024年02月13日
    浏览(41)
  • 【设计模式】责任链模式

    顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处

    2024年02月12日
    浏览(36)
  • 设计模式——责任链模式

    使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有对象处理它为止。 优点 能将请求和处理分开。请求者可以不用知道是谁处理的,处理者可以不用知道请求的全貌,两者解耦提高系

    2024年02月15日
    浏览(39)
  • 设计模式:责任链模式

    责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象按照顺序处理请求,直到其中一个对象能够处理该请求为止。责任链模式将请求发送者和接收者解耦,使得多个对象都有机会处理请求,同时避免了请求发送者与接收者之间的直接耦合关系。 在

    2024年02月07日
    浏览(41)
  • 设计模式-责任链模式

    遇到一个面试的场景题目,让实现税率的计算 请使用Java语言实现如下税率计算: 1~5000 税率 0 5001~8000 3% 8001~17000 10% 17001~30000 20% 30001~40000 25% 40001~60000 30% 60001~85000 35% 85001~ 45% 要求 ⅰ. 逻辑正确,代码优雅 ⅱ. 可扩展性,考虑区间的变化,比如说起征点从5000变成10000等等,或者

    2024年02月11日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包