查看原文
其他

责任链设计模式讲解

The following article is from 码农小胖哥 Author 码农小胖哥


  前言  

很多框架如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单元测试之JUnit 5快速上手

 高薪必备的一些Spring Boot高级面试题

● Spring Boot 2.x 中的 Actuator

● 下一代应用监控指标采集器Prometheus核心介绍

 Spring中@Async注解实现“方法”的异步调用

● 学并发编程,透彻理解这三个核心是关键

● 缓存抽象层Spring cache实战操作

● 简述设计模式原则

● 并发Bug之源有三,请睁大眼睛看清它们


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

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