【设计模式】【行为型模式】职责链模式(Chain of Responsibility)

简介: 一、入门 什么是职责链模式? 职责链模式是一种行为设计模式,它允许你将请求沿着一条链传递,直到有对象处理它为止。每个对象都有机会处理请求,或者将其传递给链中的下一个对象。 为什么需要职责链模式? 使用

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

一、入门

什么是职责链模式?

职责链模式是一种行为设计模式,它允许你将请求沿着一条链传递,直到有对象处理它为止。每个对象都有机会处理请求,或者将其传递给链中的下一个对象。

为什么需要职责链模式?

使用职责链模式的好处:

  • 解耦:发送者和处理者不直接依赖,各自独立。
  • 灵活:动态调整处理顺序,易于扩展。
  • 清晰:每个对象只处理自己能做的事,职责单一。
  • 避免硬编码:处理逻辑由链决定,代码更灵活。

怎样实现职责链模式?

责任链模式主要包含以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接(下一个对象的引用)。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

【案例】请假审批
现需要开发一个请假流程控制系统。请假一天以下的假只需要小组长同意即可;请假1天到3天的假还需要部门经理同意;请求3天到7天还需要总经理同意才行。

image.png

请假条

public class LeaveRequest {
   
    private String name;//姓名
    private int num;//请假天数
    private String content;//请假内容

    public LeaveRequest(String name, int num, String content) {
   
        this.name = name;
        this.num = num;
        this.content = content;
    }

    public String getName() {
   
        return name;
    }

    public int getNum() {
   
        return num;
    }

    public String getContent() {
   
        return content;
    }
}

处理者抽象类

public abstract class Handler {
   
    protected final static int NUM_ONE = 1;
    protected final static int NUM_THREE = 3;
    protected final static int NUM_SEVEN = 7;

    //该领导处理的请假天数区间
    private int numStart;
    private int numEnd;

    //领导上面还有领导
    private Handler nextHandler;

    //设置请假天数范围 上不封顶
    public Handler(int numStart) {
   
        this.numStart = numStart;
    }

    //设置请假天数范围
    public Handler(int numStart, int numEnd) {
   
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

    //设置上级领导
    public void setNextHandler(Handler nextHandler){
   
        this.nextHandler = nextHandler;
    }

    //提交请假条
    public final void submit(LeaveRequest leave){
   
        if(0 == this.numStart){
   
            return;
        }

        //如果请假天数达到该领导者的处理要求
        if(leave.getNum() >= this.numStart){
   
            this.handleLeave(leave);

            //如果还有上级 并且请假天数超过了当前领导的处理范围
            if(null != this.nextHandler && leave.getNum() > numEnd){
   
                this.nextHandler.submit(leave);//继续提交
            } else {
   
                System.out.println("流程结束");
            }
        }
    }

    //各级领导处理请假条方法
    protected abstract void handleLeave(LeaveRequest leave);
}

小组长

public class GroupLeader extends Handler {
   
    public GroupLeader() {
   
    //小组长处理1-3天的请假
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
   
        System.out.println(leave.getName() + "请假" + leave.getNum() +
                "天," + leave.getContent() + "。");
        System.out.println("小组长审批:同意。");
    }
}

部门经理

public class Manager extends Handler {
   
    public Manager() {
   
        //部门经理处理3-7天的请假
        super(Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
   
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("部门经理审批:同意。");
    }
}

总经理

public class GeneralManager extends Handler {
   
    public GeneralManager() {
   
        //部门经理处理7天以上的请假
        super(Handler.NUM_SEVEN);
    }

    @Override
    protected void handleLeave(LeaveRequest leave) {
   
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("总经理审批:同意。");
    }
}

测试


public class Client {
   
    public static void main(String[] args) {
   
        //请假条来一张
        LeaveRequest leave = new LeaveRequest("小花",5,"身体不适");

        //各位领导
        GroupLeader groupLeader = new GroupLeader();
        Manager manager = new Manager();
        GeneralManager generalManager = new GeneralManager();

        groupLeader.setNextHandler(manager);//小组长的领导是部门经理
        manager.setNextHandler(generalManager);//部门经理的领导是总经理
        //之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。

        //提交申请
        groupLeader.submit(leave);
    }
}

二、职责链模式在源码中的运用

2.1、Spring MVC 拦截器

Spring MVC 中的拦截器也使用了责任链模式。每个拦截器可以在请求处理前后执行特定逻辑,并决定是否继续传递请求。

2.1.1、如何使用SpringMVC拦截器?

实现HandlerInterceptor接口,并重写它的三个方法:

  • preHandle:在请求到达控制器之前执行。
  • postHandle:在控制器处理请求之后、视图渲染之前执行。
  • afterCompletion:在视图渲染之后执行(通常用于资源清理)。
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
   

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   
        System.out.println("MyInterceptor: preHandle - Before handling request");
        // 可以在这里进行权限检查、日志记录等操作
        return true; // 返回 true 表示继续传递请求,false 表示中断请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
   
        System.out.println("MyInterceptor: postHandle - After handling request, before view rendering");
        // 可以在这里修改 ModelAndView
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
   
        System.out.println("MyInterceptor: afterCompletion - After view rendering");
        // 可以在这里进行资源清理
    }
}

注册拦截器,将自定义拦截器注册到Spring MVC的配置中。可以通过实现WebMvcConfigurer接口来完成。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
   

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
   
        // 注册自定义拦截器,并指定拦截的路径
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**") // 拦截所有路径
                .excludePathPatterns("/public/**"); // 排除特定路径
    }
}

方便我们测试创建的contorlller。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {
   

    @GetMapping("/hello")
    @ResponseBody
    public String hello() {
   
        System.out.println("Controller: Handling /hello request");
        return "Hello, World!";
    }
}

运行之后的结果。

MyInterceptor: preHandle - Before handling request
Controller: Handling /hello request
MyInterceptor: postHandle - After handling request, before view rendering
MyInterceptor: afterCompletion - After view rendering

2.1.2、SpringMVC拦截器是如何实现的?

在 Spring MVC 中,HandlerExecutionChain 是责任链模式的实现核心。它包含了一个处理器(Handler)和一组拦截器(Interceptors),并负责按顺序调用这些拦截器的方法。

public class HandlerExecutionChain {
   

    private final Object handler; // 处理器(通常是Controller方法)
    private final List<HandlerInterceptor> interceptorList = new ArrayList<>(); // 拦截器列表

    // 添加拦截器
    public void addInterceptor(HandlerInterceptor interceptor) {
   
        this.interceptorList.add(interceptor);
    }

    // 执行拦截器的 preHandle 方法
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
        for (int i = 0; i < this.interceptorList.size(); i++) {
   
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
   
                // 如果某个拦截器返回 false,则中断请求
                triggerAfterCompletion(request, response, null);
                return false;
            }
        }
        return true;
    }

    // 执行拦截器的 postHandle 方法
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
   
        for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
   
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }

    // 执行拦截器的 afterCompletion 方法
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
   
        for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
   
            HandlerInterceptor interceptor = this.interceptorList.get(i);
            interceptor.afterCompletion(request, response, this.handler, ex);
        }
    }
}

DispatcherServlet 是 Spring MVC 的核心组件,它负责将请求分发给对应的处理器,并在处理过程中调用拦截器链。

public class DispatcherServlet extends FrameworkServlet {
   

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
        // 获取处理器和拦截器链
        HandlerExecutionChain mappedHandler = getHandler(request);

        // 调用拦截器的 preHandle 方法
        if (!mappedHandler.applyPreHandle(request, response)) {
   
            return; // 如果某个拦截器中断请求,则直接返回
        }

        // 调用处理器(Controller方法)
        ModelAndView mv = handle(processedRequest, response, mappedHandler.getHandler());

        // 调用拦截器的 postHandle 方法
        mappedHandler.applyPostHandle(processedRequest, response, mv);

        // 渲染视图
        render(mv, request, response);

        // 调用拦截器的 afterCompletion 方法
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

拦截器是通过 WebMvcConfigurer 接口注册的,Spring 会将这些拦截器添加到HandlerExecutionChain中。

public class InterceptorRegistration {
   

    private final HandlerInterceptor interceptor;
    private final List<String> pathPatterns = new ArrayList<>();

    public InterceptorRegistration addPathPatterns(String... patterns) {
   
        this.pathPatterns.addAll(Arrays.asList(patterns));
        return this;
    }

    public MappedInterceptor getMappedInterceptor() {
   
        return new MappedInterceptor(pathPatterns.toArray(new String[0]), null, interceptor);
    }
}

2.2、Java Web的Filter Chain

在javaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析:模拟web请求Request以及web响应Response。

public interface Request{
   

}

public interface Response{
   

}

模拟web过滤器Filter

 public interface Filter {
   
     public void doFilter(Request req,Response res,FilterChain c);
 }
模拟实现具体过滤器 
public class FirstFilter implements Filter {
   
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
   

        System.out.println("过滤器1 前置处理");

        // 先执行所有request再倒序执行所有response
        chain.doFilter(request, response);

        System.out.println("过滤器1 后置处理");
    }
}

public class SecondFilter  implements Filter {
   
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
   

        System.out.println("过滤器2 前置处理");

        // 先执行所有request再倒序执行所有response
        chain.doFilter(request, response);

        System.out.println("过滤器2 后置处理");
    }
}

模拟实现过滤器链FilterChain

public class FilterChain {
   

    private List<Filter> filters = new ArrayList<Filter>();

    private int index = 0;

    // 链式调用
    public FilterChain addFilter(Filter filter) {
   
        this.filters.add(filter);
        return this;
    }

    public void doFilter(Request request, Response response) {
   
        if (index == filters.size()) {
   
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request, response, this);
    }
}

测试

public class Client {
   
    public static void main(String[] args) {
   
        Request  req = null;
        Response res = null ;

        FilterChain filterChain = new FilterChain();
        filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
        filterChain.doFilter(req,res);
    }
}

三、总结

职责链模式:把多个处理对象连成一条链,请求按顺序传递,谁适合处理就处理,处理不了就传给下一个。

优点

  • 解耦:发请求的不用关心谁来处理,处理者之间也不互相依赖。
  • 灵活:能动态调整链条顺序,或增删处理步骤。
  • 单一职责:每个处理者只做自己该做的事。

缺点

  • 可能没人处理:链条没配好时,请求可能“走完全场”也没结果。
  • 性能问题:链条太长时,传递过程拖慢速度。
  • 调试麻烦:请求的传递路径不直观,排查问题费劲。

适用场景

  • 需要动态切换算法或行为:例如,支付方式、排序算法、资源加载策略等。
  • 有多个相似的类,只有行为不同:例如,不同类型的折扣计算、不同的日志记录方式等。
  • 避免使用复杂的条件语句:当代码中有大量if-else或switch-case语句时,可以用策略模式替代。
  • 需要隔离算法的实现细节:当不希望暴露算法的实现细节,或者希望算法可以独立变化时。
  • 需要对算法进行扩展:当系统需要支持新的算法,且不希望修改现有代码时。

参考

黑马程序员Java设计模式详解, 23种Java设计模式(图解+框架源码分析+实战)_哔哩哔哩_bilibili

目录
相关文章
|
6月前
|
设计模式 网络协议 Java
【设计模式】【行为型模式】状态模式(State)
一、入门 什么是状态模式? 状态模式(State Pattern)是一种行为设计模式,允许对象在其内部状态改变时改变其行为,使其看起来像是改变了类。状态模式的核心思想是将对象的状态封装成独立的类,并将
292 16
|
6月前
|
设计模式 存储 Java
【设计模式】【行为型模式】备忘录模式(Memento)
一、入门 什么是备忘录模式? 备忘录模式(Memento Pattern)是一种行为设计模式,用于在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在需要时恢复该状态。它通常用于实现撤销操作
221 8
|
6月前
|
设计模式 消息中间件 Java
【设计模式】【行为型模式】命令模式(Command)
一、入门 什么是命令模式? 命令模式是一种行为设计模式,它将请求或操作封装为对象,从而使你可以用不同的请求对客户进行参数化,并支持请求的排队、记录、撤销等操作。 命令模式的核心是将“请求”封装为独立的
226 15
|
6月前
|
设计模式 Java 编译器
【设计模式】【行为型模式】解释器模式(Interpreter)
一、入门 什么是解释器模式? 解释器模式(Interpreter Pattern)是一种行为设计模式,用于定义语言的语法表示,并提供一个解释器来处理该语法。它通常用于需要解释和执行特定语言或表达式的场
169 11
|
6月前
|
设计模式 存储 JavaScript
【设计模式】【行为型模式】迭代器模式(Iterator)
一、入门 什么是迭代器模式? 迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种顺序访问聚合对象中元素的方法,而不需要暴露其底层表示。迭代器模式将遍历逻辑从聚合对象中分离出
173 11
|
6月前
|
设计模式 XML JSON
【设计模式】【行为型模式】访问者模式(Visitor)
一、入门 什么是访问者模式? 访问者模式(Visitor Pattern)是一种行为设计模式,允许你将算法与对象结构分离。通过这种方式,可以在不改变对象结构的情况下,向对象结构中的元素添加新的操作。
224 10
|
6月前
|
设计模式 Java 程序员
【设计模式】【行为型模式】中介者模式(Mediator)
一、入门 什么是中介者模式? 中介者模式(Mediator Pattern)是一种行为设计模式,旨在减少对象之间的直接依赖,通过引入一个中介者对象来协调多个对象之间的交互。这种模式特别适用于对象间存在
156 9
|
6月前
|
设计模式 消息中间件 存储
【设计模式】【行为型模式】观察者模式(Observer)
一、入门 什么是观察者模式? 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
340 9
|
6月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
200 16
|
6月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
207 0