XiaoLin's Blog

Xiao Lin

责任链设计模式学习笔记

8
2024-02-26

责任链设计模式(Chain of Responsibility Pattern)是一种行为设计模式,它旨在将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。在这种模式下,请求从一个对象传递到另一个对象,形成一条链,直到有一个对象处理这个请求为止。

核心组成

责任链模式主要包括以下几个核心组件:

  1. 处理器(Handler)接口:定义了处理请求的方法。所有具体处理器都需要实现这个接口。
  2. 具体处理器(Concrete Handler):实现处理器接口的类。它会尝试处理接收到的请求;如果能够处理,则进行处理;如果不能,则将请求转发给它的后继者。
  3. 客户端(Client):负责创建责任链,并向链上的某个处理器对象发起请求。

工作原理

  • 客户端向责任链上的第一个处理器发送请求。
  • 每个处理器接收到请求后,决定自己是否有能力进行处理。
    • 如果可以,则该处理器会“消费”这个请求,完成相应操作。
    • 如果不能,则将该请求转发给它在责任链中的后继者。
  • 这个过程会一直持续下去,直到找到一个合适的处理器或者整条链都无法处理这个请求。

应用场景

责任链模式特别适用于以下情况:

  • 有多个对象可以处理同一请求时,但具体由哪个对象来处理该请求在运行时才确定。
  • 想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  • 可以动态地指定一组对象来处理请求。

优缺点

优点

  • 降低耦合度:它将请求的发送者和接收者解耦。
  • 增强了系统灵活性:可以动态地添加或修改责任链上的成员。
  • 增加了给对象指派职责的灵活性:通过改变链内成员或调整它们的顺序,允许动态地新增或删除责任。

缺点

  • 性能问题:每一个请求都是从链头开始遍历直到找到合适的处理者。如果责任链很长,则可能影响性能。
  • 调试困难:特别是在责任链较长、并且涉及到实时交互时,理解和调试责任链可能会比较复杂。

实现方式

链表实现

第一种实现方式如下所示。其中,Handler 是所有处理器类的抽象父类,handle() 是抽象方法。每个具体的处理器类(HandlerA、HandlerB)的 handle() 函数的代码结构类似,如果它能处理该请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理(也就是调用 successor.handle())。HandlerChain 是处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录链尾是为了方便添加处理器。

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * 责任链设计模式 - 链表方式实现  
 *  
 * 处理器接口  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public interface Handler {  
  
    /**  
     * 处理  
     *  
     * @return boolean  
     * @author huangmuhong  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     boolean handle();  
  
    /**  
     * 获取下一个处理器  
     *  
     * @return {@link Handler }  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     Handler getNext();  
  
    /**  
     * 设置下一个处理器  
     *  
     * @param handler 下一个处理器  
     * @return void  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     void setNext(Handler handler);  
  
}

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public abstract class AbstractHandler implements Handler {  
  
    private Handler next;  
  
    @Override  
    public Handler getNext() {  
        return next;  
    }  
  
    @Override  
    public void setNext(Handler handler) {  
        this.next = handler;  
    }  
}

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * 责任链设计模式 - 链表实现  
 *  
 * 具体处理器  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 * @see Handler  
 */  
public class AHandler extends AbstractHandler {  
    @Override  
    public boolean handle() {  
        System.out.println("AHandler handle");  
        boolean handled = false;  
        //...  
        if (!handled && getNext() != null) {  
            return getNext().handle();  
        }  
        return handled;  
    }  
}

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * 责任链设计模式 - 链表实现  
 *  
 * 具体处理器  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 * @see Handler  
 */  
public class BHandler extends AbstractHandler {  
    @Override  
    public boolean handle() {  
        System.out.println("BHandler handle");  
        boolean handled = false;  
        //...  
        if (!handled && getNext() != null) {  
            return getNext().handle();  
        }  
        return handled;  
    }  
}

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * 处理器链  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public class HandleChain {  
  
    private Handler head;  
  
    private Handler tail;  
  
    /**  
     * 添加处理程序  
     *  
     * @param handler 处理程序  
     * @author huangmuhong  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     public void addHandler(Handler handler) {  
        handler.setNext(null);  
        if (head == null) {  
            head = handler;  
            tail = handler;  
            return;  
        }  
        tail.setNext(handler);  
        tail = handler;  
    }  
  
    /**  
     * 处理  
     *  
     * @author huangmuhong  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     public void handle() {  
        if (head != null) {  
            head.handle();  
        }  
    }  
  
}

package xyz.xiaolinz.demo.chain.linked;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class Main {  
    public static void main(String[] args) {  
        final HandleChain handleChain = new HandleChain();  
        handleChain.addHandler(new AHandler());  
        handleChain.addHandler(new BHandler());  
  
        handleChain.handle();  
    }  
}

实际上,上面的代码实现不够优雅。处理器类的 handle() 函数,不仅包含自己的业务逻辑,还包含对下一个处理器的调用。

数组实现

这种实现方式更加简单。HandlerChain 类用数组而非链表来保存所有的处理器,并且需要在 HandlerChain 的 handle() 函数中,依次调用每个处理器的 handle() 函数。

package xyz.xiaolinz.demo.chain.array;  
  
/**  
 * 责任链设计模式 - 链表方式实现  
 *  
 * 处理器接口  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public interface Handler {  
  
    /**  
     * 处理  
     *  
     * @return boolean  
     * @author huangmuhong  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     boolean handle();  
  
}

package xyz.xiaolinz.demo.chain.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class AHandler implements Handler {  
    @Override  
    public boolean handle() {  
        System.out.println("AHandler handle");  
        boolean handled = false;  
        //...  
        return handled;  
    }  
}

package xyz.xiaolinz.demo.chain.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class BHandler implements Handler {  
    @Override  
    public boolean handle() {  
        System.out.println("BHandler handle");  
        boolean handled = false;  
        //...  
        return handled;  
    }  
}

package xyz.xiaolinz.demo.chain.array;  
  
import java.util.ArrayList;  
import java.util.Collections;  
import java.util.List;  
  
/**  
 * 手柄链  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public class HandleChain {  
  
    private final List<Handler> handlers = new ArrayList<>();  
  
    public void addHandler(Handler... handlers) {  
        Collections.addAll(this.handlers, handlers);  
    }  
  
    /**  
     * 处理  
     *  
     * @return void  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     public void handle() {  
        for (Handler handler : handlers) {  
            if (handler.handle()) {  
                break;  
            }  
        }  
    }  
}

package xyz.xiaolinz.demo.chain.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class Main {  
    public static void main(String[] args) {  
        final HandleChain handleChain = new HandleChain();  
        handleChain.addHandler(new AHandler());  
        handleChain.addHandler(new BHandler());  
  
        handleChain.handle();  
    }  
}

特殊用法

在 GoF 给出的定义中,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况。

根据上述描述,我们的责任链不会因为产生中间状态而停止调用下一个处理器,所以并不需要具体的返回值,所有的中间状态都可以通过入参进行统一的传递

数组实现

package xyz.xiaolinz.demo.chain.mutate.array;  
  
/**  
 * 处理程序  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public interface Handler {  
  
    /**  
     * 处理  
     *  
     * @author huangmuhong  
     * @date 2024/02/20  
     * @since 1.0.0  
     */    
     void handle();  
}

package xyz.xiaolinz.demo.chain.mutate.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class AHandler implements Handler {  
    @Override  
    public void handle() {  
        System.out.println("AHandler handle");  
        //...  
  
    }  
}

package xyz.xiaolinz.demo.chain.mutate.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class BHandler implements Handler {  
    @Override  
    public void handle() {  
        System.out.println("BHandler handle");  
        //...  
    }  
}

package xyz.xiaolinz.demo.chain.mutate.array;  
  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.List;  
  
/**  
 * 处理链  
 *  
 * @author huangmuhong  
 * @version 1.0.0  
 * @date 2024/02/20  
 */
 public class HandlerChain {  
  
    private final List<Handler> handlers = new ArrayList<>();  
  
    public void addHandler(Handler... handlers) {  
        this.handlers.addAll(Arrays.asList(handlers));  
    }  
  
    public void handle() {  
        for (Handler handler : handlers) {  
            handler.handle();  
        }  
    }  
}

package xyz.xiaolinz.demo.chain.mutate.array;  
  
/**  
 * @author huangmuhong  
 * @date 2024/2/20  
 */
 public class Main {  
    public static void main(String[] args) {  
        final HandlerChain handleChain = new HandlerChain();  
        handleChain.addHandler(new AHandler());  
        handleChain.addHandler(new BHandler());  
  
        handleChain.handle();  
    }  
}

递归实现

在平时的 servlet web工程中经常使用的过滤器Filter其实也是基于责任链设计模式的思想设计的,他就是责任链中的变体,依次调用注册的过滤器直到所有过滤器调用或者抛出异常后才结束,我们可以参考他的源码
Servlet Filter 是 Java Servlet 规范中定义的组件,翻译成中文就是过滤器,它可以实现对 HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等等。因为它是 Servlet 规范的一部分,所以,只要是支持 Servlet 的 Web 容器(比如,Tomcat、Jetty 等),都支持过滤器功能。为了帮助你理解,我画了一张示意图阐述它的工作原理,如下所示。
image.png

我们查看 Filter 接口的源码

package javax.servlet;

import java.io.IOException;

public interface Filter {

    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException;

    default void destroy() {
    }
}

可以看到,在具体需要实现的方法doFilter中有一个FilterChain 属性,该属性是用来递归调用过滤器链的。

如何递归调用下一个过滤器:

package xyz.tiegangan.capability.platform.server.test.filter;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public class TestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

我们可以通过FilterChain接口的实现类ApplicationFilterChain中查看到他具体的递归调用逻辑,以下是核心逻辑的代码片段。

/**

 * Invoke the next filter in this chain, passing the specified request and response. If there are no more filters in

 * this chain, invoke the <code>service()</code> method of the servlet itself.

 *

 * @param request  The servlet request we are processing

 * @param response The servlet response we are creating

 *

 * @exception IOException      if an input/output error occurs

 * @exception ServletException if a servlet exception occurs

 */

@Override

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {

    // 当`Globals.IS_SECURITY_ENABLED`为`true`时,会执行一个特定的代码块,这段代码使用了Java的安全API来执行`internalDoFilter`方法。这是为了在Java的安全管理器启用的情况下,确保对`internalDoFilter`方法的调用是在一个受控的安全上下文中进行的。
    if (Globals.IS_SECURITY_ENABLED) {

        final ServletRequest req = request;

        final ServletResponse res = response;

        try {

            java.security.AccessController.doPrivileged((java.security.PrivilegedExceptionAction<Void>) () -> {

                internalDoFilter(req, res);

                return null;

            });

        } catch (PrivilegedActionException pe) {

            Exception e = pe.getException();

            if (e instanceof ServletException) {

                throw (ServletException) e;

            } else if (e instanceof IOException) {

                throw (IOException) e;

            } else if (e instanceof RuntimeException) {

                throw (RuntimeException) e;

            } else {

                throw new ServletException(e.getMessage(), e);

            }

        }

    } else {
        // 调用过滤器
        internalDoFilter(request, response);

    }

}

private void internalDoFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
    // 如果还有未执行的过滤器,继续执行下一个过滤器
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();

            // 如果请求支持异步处理,但过滤器不支持,设置请求属性ASYNC_SUPPORTED_ATTR为false
            if (request.isAsyncSupported() &&
                    "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
            }
            // 如果安全管理器启用,以特权方式执行过滤器的doFilter方法
            if (Globals.IS_SECURITY_ENABLED) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal = ((HttpServletRequest) req).getUserPrincipal();

                Object[] args = new Object[] { req, res, this };
                SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
            } else {
                // 普通方式执行过滤器的doFilter方法
                filter.doFilter(request, response, this);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
        return;
    }

    // 执行到过滤器链的末尾,调用Servlet实例
    try {
        // 如果dispatcherWrapsSameObject为true,记录当前请求和响应
        if (dispatcherWrapsSameObject) {
            lastServicedRequest.set(request);
            lastServicedResponse.set(response);
        }

        // 如果请求支持异步处理,但Servlet不支持,设置请求属性ASYNC_SUPPORTED_ATTR为false
        if (request.isAsyncSupported() && !servletSupportsAsync) {
            request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
        }
        // 如果安全管理器启用,以特权方式执行Servlet的service方法
        if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal = ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[] { req, res };
            SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal);
        } else {
            // 普通方式执行Servlet的service方法
            servlet.service(request, response);
        }
    } catch (IOException | ServletException | RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        e = ExceptionUtils.unwrapInvocationTargetException(e);
        ExceptionUtils.handleThrowable(e);
        throw new ServletException(sm.getString("filterChain.servlet"), e);
    } finally {
        // 如果dispatcherWrapsSameObject为true,清除记录的请求和响应
        if (dispatcherWrapsSameObject) {
            lastServicedRequest.set(null);
            lastServicedResponse.set(null);
        }
    }
}

我们模仿Filter的思路,实现一个递归版本的责任链

  1. 定义一个HandleChain接口,这是我们的递归调度接口
package xyz.xiaolinz.demo.chain.mutate.recurve;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public interface HandlerChain {

    /**
     * 处理
     *
     * @param context 上下文
     * @author huangmuhong
     * @date 2024/02/23
     * @since 1.0.0
     */
    void handle(Context context);

}

  1. 定义Handler接口,处理器角色
package xyz.xiaolinz.demo.chain.mutate.recurve;

/**
 * 处理器
 *
 * @author huangmuhong
 * @version 1.0.0
 * @date 2024/02/23
 */
public interface Handler {

    /**
     * 处理
     *
     * @param context      上下文
     * @param handlerChain 处理链
     * @author huangmuhong
     * @date 2024/02/23
     * @since 1.0.0
     */
    void handle(Context context, HandlerChain handlerChain);

    /**
     * 排序
     *
     * @return int
     * @author huangmuhong
     * @date 2024/02/23
     * @since 1.0.0
     */
    int order();

}
  1. 定义HandlerChainHandle类,用于实现链的调度与管理,并在内部实现HandlerChain的具体逻辑
package xyz.xiaolinz.demo.chain.mutate.recurve;

import java.util.List;

/**
 * 处理程序链处理程序
 *
 * @author huangmuhong
 * @version 1.0.0
 * @date 2024/02/23
 */
public class HandlerChainHandler {

    private List<Handler> handlers;

    public HandlerChainHandler(List<Handler> handlers) {
        this.handlers = handlers;
    }

    /**
     * 处理
     *
     * @author huangmuhong
     * @date 2024/02/23
     * @since 1.0.0
     */
    public void handle(Context context) {
        // 排序过滤器链
        handlers.sort(Comparator.comparingInt(Handler::order));

        // 递归调用
        new DefaultHandlerChain(handlers).handle(context);
    }

    /**
     * 默认处理程序链
     *
     * @author huangmuhong
     * @version 1.0.0
     * @date 2024/02/23
     * @see HandlerChain
     */
    static class DefaultHandlerChain implements HandlerChain {
        private final List<Handler> handlers;

        private int pos;

        public DefaultHandlerChain(List<Handler> handlers) {
            this.handlers = handlers;
            this.pos = 0;
        }

        @Override
        public void handle(Context context) {
            if (pos < handlers.size()) {
                Handler handler = handlers.get(pos++);
                handler.handle(context, this);
            }
        }
    }
}
  1. 定义几个默认的过滤器链实现
package xyz.xiaolinz.demo.chain.mutate.recurve;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public class AHandler implements Handler {
    @Override
    public void handle(Context context, HandlerChain handlerChain) {
        System.out.println("这里是AHandler,我将是第一个处理器,上下文中的数据是:" + context.getDesc());
        handlerChain.handle(context);
    }

    @Override
    public int order() {
        return 1;
    }
}

package xyz.xiaolinz.demo.chain.mutate.recurve;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public class BHandler implements Handler {
    @Override
    public void handle(Context context, HandlerChain handlerChain) {
        System.out.println("这里是BHandler,我将是第三个处理器,上下文中的数据是:" + context.getDesc());
        handlerChain.handle(context);
    }

    @Override
    public int order() {
        return 3;
    }
}

package xyz.xiaolinz.demo.chain.mutate.recurve;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public class CHandler implements Handler {
    @Override
    public void handle(Context context, HandlerChain handlerChain) {
        System.out.println("这里是CHandler,我将是第二个处理器,上下文中的数据是:" + context.getDesc());
        handlerChain.handle(context);
    }

    @Override
    public int order() {
        return 2;
    }
}
  1. 通过HandlerChainHandler动态的递归调用这些处理器
package xyz.xiaolinz.demo.chain.mutate.recurve;

import java.util.ArrayList;

/**
 * @author huangmuhong
 * @date 2024/2/23
 */
public class Main {
    public static void main(String[] args) {
        Context context = new Context();
        context.setDesc("This is a context.");
        final ArrayList<Handler> handlers = new ArrayList<>();
        handlers.add(new AHandler());
        handlers.add(new BHandler());
        handlers.add(new CHandler());

        final HandlerChainHandler handlerChainHandler = new HandlerChainHandler(handlers);
        handlerChainHandler.handle(context);

    }
}

结果: