zoukankan      html  css  js  c++  java
  • 责任链模式

    定义

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

    使用场景

    如果一个请求可能会出现多个或未知个数处理器实例,或者请求处理器可动态配置的情况下,这时候便可使用责任链模式。
    几乎所有的开源框架中都使用到该模式,如 Spring 中的拦截器、过滤器,通过 ant 表达式风格的 url 参数来判断是否对请求进行拦截,Netty 中 ChannelPipeLine 通过链表的形式添加 ChannelHandler 处理节点。

    在SpringBoot中使用

    结构图

    chain.jpg

    责任链的处理核心在"链"(Chain)上面。"链"是由多个处理者 ConcreateX 组成的,我们先来看抽象 “Handler” 接口:

    /**
     * @author tianp
     **/
    public interface Handler {
        /**
         * 是否支持处理
         *
         * @param uri 匹配uri
         * @return true 成功 false 失败
         */
        boolean support(String uri);
    
        /**
         * 处理
         *
         * @param requestBody 处理参数封装
         * @return true 成功 false 失败
         */
        boolean handle(RequestBody requestBody);
    
        /**
         * 获取处理器名字
         *
         * @return 处理器名字
         */
        String getName();
    
    }
    
    

    RequestBody 对请求的参数进行封装

    
    /**
     * 请求处理封装类
     *
     * @author tianp
     **/
    public class RequestBody {
        private String uri;
        //根据业务定义
        private Object body;
    
        public String getUri() {
            return uri;
        }
    
        public void setUri(String uri) {
            this.uri = uri;
        }
    
        public Object getBody() {
            return body;
        }
    
        public void setBody(Object body) {
            this.body = body;
        }
    }
    
    

    处理器接口 “Hanlder” 定义了三个标准:

    • 是否支持处理。通过参数 uri 判断当前 “Handler” 是否支持处理, 如果当前不能处理就传递给下一个 “Handler” 处理
    • 真正进行处理的方法。传递 RequestBody给 handle 方法,处理成功则传递下一个,不成功则返回false,结束。
    • 获取当前处理器名字。便于打印日志排查问题
    
    /**
     * @author tianp
     **/
    public abstract class AbstractHandler implements Handler {
        /**
         * 处理器名称
         */
        private String name;
        /**
         * 拦截uri
         */
        private String[] includePatterns;
    
        /**
         * 放行uri
         */
        private String[] excludePatterns;
    
        /**
         * ant 匹配
         */
        private PathMatcher pathMatcher = new AntPathMatcher();
        /**
         * 下一个处理器
         */
        private AbstractHandler next = null;
    
        public AbstractHandler(String name) {
            this.name = name;
        }
    
        public boolean support(String uri) {
            if (excludePatterns != null) {
                for (String exclude : excludePatterns) {
                    if (pathMatcher.match(exclude, uri)) {
                        return false;
                    }
                }
            }
            if (includePatterns != null) {
                for (String include : includePatterns) {
                    if (pathMatcher.match(include, uri)) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        /**
         * 给子类实现的真正处理方法
         *
         * @param requestBody 请求参数
         * @return true 成功 false 失败
         */
        public abstract boolean process(RequestBody requestBody);
    
        public boolean handle(RequestBody requestBody) {
            if (next != null) {
                if (next.support(requestBody.getUri())) {
                    System.out.println(next.getName() + "开始处理");
                    return next.process(requestBody);
                } else {
                    next.handle(requestBody);
                }
            }
            return true;
        }
    }
    //.... 省略 get/set 方法
    

    抽象处理器 AbstractHandler 实现了 Handler 接口,实现了对应的

    • support() 通过 AntPathMatcher 使用 ant 风格的表达式来匹配当前类是否支持拦截
    • handle() 通过持有一个 next 指针来进行请求传递
    • getName()
    • process() 给子类实现的真正处理的方法
    /**
     * @author tianp
     **/
    public class LinkedHandlerChain {
        /**
         * 头节点
         */
        private static final AbstractHandler HEAD = new AbstractHandler("head"){
    
            @Override
            public boolean process(RequestBody requestBody) {
                return true;
            }
        };
        private AbstractHandler TAIL = HEAD;
        public void addLast(AbstractHandler handler){
            TAIL.setNext(handler);
            TAIL = handler;
        }
        public boolean handle(RequestBody requestBody){
           return HEAD.handle(requestBody);
        }
    }
    

    最后通过一个链 LinkedhandlerChain 串起来。通过持有链表的指针 HEAD、TAIL 来处理和添加节点。

    优点

    非常显著的优点就是将请求和处理分开。请求者不用知道是谁处理的,处理者不用知道请求的全貌。两者解耦,提高系统灵活性

    缺点

    1. 性能问题。每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
    2. 调试不方便。当链比较长、环节比较多的时候,由于采取了类似递归的方式,调试的时候逻辑可能比较复杂

    最佳实践

    责任链在实际项目中,曾经在项目中使用它来对一部分功能进行鉴权,因为当时只有一部分接口需要鉴权,如果引入第三方框架如:Spring Security 和 Shiro 不仅增加项目的复杂度,还让项目变 “重”,因此通过引入 责任链模式,我可以很好的解决这个问题

    更多参考

    代码仓库地址:https://github.com/To-echo/chain-design/tree/master

    参考书籍:《设计模式之禅》

  • 相关阅读:
    ios中的XMPP简介
    iOS项目开发中的目录结构
    ios中怎么样点击背景退出键盘
    ios中怎么处理键盘挡住输入框
    ios中怎么样调节占位文字与字体大小在同一高度
    ios中怎么样设置drawRect方法中绘图的位置
    ios中用drawRect方法绘图的时候设置颜色
    字符串常见操作
    字典、列表、元组
    字符串查看及应用
  • 原文地址:https://www.cnblogs.com/coding400/p/11596309.html
Copyright © 2011-2022 走看看