查看原文
其他

责任链设计模式讲解

码农小胖哥 码农小胖哥 2020-10-17

  前言  

很多框架如mybatis,servlet的filter,dubbo,安全框架诸如Spring security、apache shiro都会用到设计模式中的责任链模式,所以学习责任链模式成为帮助你学习以上这些框架的一个好的手段之一。今天我们就来了解一下责任链模式。


  定义  


如果有多个对象(Handler)都有机会处理数据源(RequestSource,这里不是单纯的数据库数据源,可以是一个请求,总之是来源),责任链可以使数据的发送者和接收者解耦,数据沿着责任链传递,直到有一个对象处理了它为止。形成了一条流水线的链条,所以称之为责任链,但是不仅仅局限于链条,还可以成树形或者环形,这取决于你的业务设计。


  场景  


插件设计、拦截器、过滤器等一些针对切入点的特定链式处理。都可以使用责任链模式。


实现方式


实现方式常用有两种,它们的不同主要是定义处理链的顺序和结构的不同,接下来我们来看看这两种方式。


 方式一 


通过处理器集合来定义处理顺序。好处在于可以集中管理处理器,指责单一。非常容易理解,容易实现。缺点是如果新增处理器(Handler)势必影响已有的处理器,只能顺序执行。处理流程是这样的:



接下来用代码来实现一下此模式:


HandlerChain 负责维护调用链条的顺序,这里默认实现用List来管理Handler


public interface HandlerChain {

    /**
     * 调用handler 处理 source.
     *
     * @param requestSource the request source
     */


    void doChain(RequestSource requestSource);
}



// 实现

public class DefaultHandlerChain implements HandlerChain {

    // 当前handler指针的位置
    private int pos = 0;
    private List<Handler> handlers = new ArrayList<>();

    public void addHandler(Handler handler) {
        handlers.add(handler);
    }


    @Override

    public void doChain(RequestSource requestSource) {
        int size = handlers.size();
        if (pos < size) {
          //注意对pos的处理
            Handler handler = handlers.get(pos++);
            handler.doHandler(requestSource, this);
        }
    }
}

 

Handler是处理链的节点抽象,是数据源(RequestSource)的具体处理者,它负责对数据的处理以及决定是否进入下一个Handler。


 

public interface Handler {

    /**
     * Do handler.
     *
     * @param requestSource 数据源
     * @param handlerChain 传入当前的Chain进行类似递归式的调用。
     */


    void doHandler(RequestSource requestSource,HandlerChain handlerChain);

}



// 其中一个实现

public class HeaderHandler implements Handler {
    @Override
    public void doHandler(RequestSource requestSource, HandlerChain handlerChain) {

       // 处理数据
        Integer header = requestSource.getHeader();
        System.out.println("header handler= " + header);
       //继续下一个 你可以根据条件来决定是否继续进行chain
        handlerChain.doChain(requestSource);
    }
}


 方式二 


该方式利用链表的指针特性。这里利用了链表的一部分特点,通过在当前的Handler指定下一个Handler来作为指针,相比较上面而言,Handler更自治,在节点的处理上更加灵活。




Handler负责指针以及逻辑处理:


 

public interface Handler {

    /**

     * 指针指向下一个处理节点.
     *
     * @return the next
     */


    Handler getNext();


    /**
     * 处理具体逻辑.
     *
     * @param requestSource the request source
    */


    void doHandler(RequestSource requestSource);

}



// 实现

public class HeaderHandler implements Handler {

    private Handler next;

    public HeaderHandler(Handler next) {
        this.next = next;
    }

    @Override
    public Handler getNext() {
        return next;
    }

    @Override
    public void doHandler(RequestSource requestSource) {

        Integer header = requestSource.getHeader();
        System.out.println("header = " + header);
        if (next != null) {
            next.doHandler(requestSource);
        }
    }
}

  总结  


责任链模式在各种常见框架中非常常见。所以建议各位在对此设计模式进行认真学习。 


demo地址:https://gitee.com/felord/chain-pattern.git

●  Java Web 面试中关于Spring MVC的必问题,不收藏血亏!

●  Nginx(八)-- Nginx+keepalived实现高可用

●  Springboot与Elasticsearch完美结合


Modified on

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存