设计模式-责任链模式:让请求在链条中流动直到被处理

设计模式-责任链模式:让请求在链条中流动直到被处理

在日常开发中,我们经常遇到这样的场景:一个请求需要经过多个对象的处理,每个对象都有可能处理这个请求,但具体由哪个对象处理在运行时才能确定。比如请假审批流程、过滤敏感词、异常处理等。如果使用传统的if-else嵌套,代码会变得臃肿且难以维护。

有一种优雅解决这类问题的设计模式------责任链模式

1. 什么是责任链模式?

责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行发送。收到请求后,每个处理者都可以处理请求,或将其传递给链上的下一个处理者。

简单来说,责任链模式的核心思想是:

  • 多个处理者:将多个处理者对象连接成一条链
  • 传递请求:请求沿着这条链传递,直到被某个处理者处理
  • 动态处理:处理者可以动态地增加或减少,处理顺序也可以动态调整

2. 从一个实际问题开始

假设我们要实现一个请假审批系统:

  • 1天以内的请假,组长可以审批
  • 3天以内的请假,经理可以审批
  • 7天以内的请假,总监可以审批
  • 超过7天的请假,需要CEO审批

如果不使用设计模式,我们可能会写出这样的代码:

java 复制代码
// 反面教材:使用复杂的if-else嵌套
public class LeaveApproval {
    public boolean approve(LeaveRequest request) {
        int days = request.getDays();
        
        if (days <= 1) {
            // 组长审批逻辑
            System.out.println("组长审批通过");
            return true;
        } else if (days <= 3) {
            // 经理审批逻辑
            System.out.println("经理审批通过");
            return true;
        } else if (days <= 7) {
            // 总监审批逻辑
            System.out.println("总监审批通过");
            return true;
        } else {
            // CEO审批逻辑
            System.out.println("CEO审批通过");
            return true;
        }
    }
}

这段代码的问题:

  1. 违反开闭原则:新增审批级别需要修改原有代码
  2. 职责不清晰:一个方法负责了所有审批逻辑
  3. 难以维护:随着审批规则复杂化,代码会越来越臃肿

3. 责任链模式的结构

责任链模式包含三个核心角色:
nextHandler
nextHandler
使用
<<interface>>
Handler
+setNext(handler) : void
+handle(request) : void
ConcreteHandlerA
-nextHandler: Handler
+handle(request) : void
ConcreteHandlerB
-nextHandler: Handler
+handle(request) : void
Client
+sendRequest(request) : void

  • 抽象处理者:定义处理请求的接口,通常包含设置下一个处理者的方法
  • 具体处理者:实现抽象处理者,处理自己负责的请求,不能处理则传递给下一个
  • 客户端:创建处理链,并向链头发送请求

4. 责任链模式的Java实现

让我们用责任链模式重构请假审批系统:

步骤1:定义请求类

java 复制代码
/**
 * 请假请求类
 */
public class LeaveRequest {
    private String employeeName;  // 员工姓名
    private int days;            // 请假天数
    private String reason;       // 请假原因
    
    public LeaveRequest(String employeeName, int days, String reason) {
        this.employeeName = employeeName;
        this.days = days;
        this.reason = reason;
    }
    
    // Getter方法
    public String getEmployeeName() {
        return employeeName;
    }
    
    public int getDays() {
        return days;
    }
    
    public String getReason() {
        return reason;
    }
}

步骤2:定义抽象处理者

java 复制代码
/**
 * 抽象审批者(处理者)
 */
public abstract class Approver {
    protected Approver nextApprover;  // 下一个审批者
    protected String name;            // 审批者姓名
    protected int maxDays;            // 最大审批天数
    
    public Approver(String name, int maxDays) {
        this.name = name;
        this.maxDays = maxDays;
    }
    
    /**
     * 设置下一个审批者
     */
    public Approver setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
        return this.nextApprover;  // 返回下一个审批者,支持链式调用
    }
    
    /**
     * 处理请假请求
     */
    public void processRequest(LeaveRequest request) {
        if (request.getDays() <= maxDays) {
            // 能够处理该请求
            System.out.println(name + "审批通过");
            System.out.println("员工:" + request.getEmployeeName());
            System.out.println("天数:" + request.getDays() + "天");
            System.out.println("原因:" + request.getReason());
            System.out.println("-----------------------");
        } else if (nextApprover != null) {
            // 传递给下一个审批者
            System.out.println(name + "无法审批,转交给上级");
            nextApprover.processRequest(request);
        } else {
            // 没有下一个审批者,无法处理
            System.out.println("请假天数过长,无人能够审批");
            System.out.println("员工:" + request.getEmployeeName());
            System.out.println("天数:" + request.getDays() + "天(超过最大审批天数)");
            System.out.println("-----------------------");
        }
    }
}

步骤3:实现具体处理者

java 复制代码
/**
 * 组长审批者(可以审批1天以内的请假)
 */
public class GroupLeader extends Approver {
    public GroupLeader(String name) {
        super(name, 1);  // 组长最多审批1天
    }
}

/**
 * 经理审批者(可以审批3天以内的请假)
 */
public class Manager extends Approver {
    public Manager(String name) {
        super(name, 3);  // 经理最多审批3天
    }
}

/**
 * 总监审批者(可以审批7天以内的请假)
 */
public class Director extends Approver {
    public Director(String name) {
        super(name, 7);  // 总监最多审批7天
    }
}

/**
 * CEO审批者(可以审批任何天数的请假)
 */
public class CEO extends Approver {
    public CEO(String name) {
        super(name, Integer.MAX_VALUE);  // CEO可以审批任何天数
    }
    
    @Override
    public void processRequest(LeaveRequest request) {
        // CEO特殊处理:需要记录详细日志
        System.out.println(name + "(CEO)审批通过 - 重要记录备案");
        System.out.println("员工:" + request.getEmployeeName());
        System.out.println("天数:" + request.getDays() + "天");
        System.out.println("原因:" + request.getReason());
        System.out.println("审批时间:" + new java.util.Date());
        System.out.println("-----------------------");
    }
}

步骤4:客户端使用

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 1. 创建审批链
        System.out.println("=== 创建审批链 ===");
        Approver groupLeader = new GroupLeader("张组长");
        Approver manager = new Manager("李经理");
        Approver director = new Director("王总监");
        Approver ceo = new CEO("陈总");
        
        // 构建责任链:组长 -> 经理 -> 总监 -> CEO
        groupLeader.setNextApprover(manager);
        manager.setNextApprover(director);
        director.setNextApprover(ceo);
        
        // 2. 创建请假请求
        System.out.println("\n=== 处理请假请求 ===");
        
        // 请假半天 - 组长审批
        LeaveRequest request1 = new LeaveRequest("张三", 1, "感冒发烧");
        groupLeader.processRequest(request1);
        
        // 请假2天 - 经理审批
        LeaveRequest request2 = new LeaveRequest("李四", 2, "家里有事");
        groupLeader.processRequest(request2);
        
        // 请假5天 - 总监审批
        LeaveRequest request3 = new LeaveRequest("王五", 5, "旅游度假");
        groupLeader.processRequest(request3);
        
        // 请假10天 - CEO审批
        LeaveRequest request4 = new LeaveRequest("赵六", 10, "婚假");
        groupLeader.processRequest(request4);
        
        // 3. 动态修改责任链
        System.out.println("\n=== 动态修改责任链(跳过总监) ===");
        // 修改链:组长 -> 经理 -> CEO
        manager.setNextApprover(ceo);
        
        LeaveRequest request5 = new LeaveRequest("孙七", 6, "病假");
        groupLeader.processRequest(request5);
    }
}

输出结果:

复制代码
=== 创建审批链 ===

=== 处理请假请求 ===
张组长审批通过
员工:张三
天数:1天
原因:感冒发烧
-----------------------
张组长无法审批,转交给上级
李经理审批通过
员工:李四
天数:2天
原因:家里有事
-----------------------
张组长无法审批,转交给上级
李经理无法审批,转交给上级
王总监审批通过
员工:王五
天数:5天
原因:旅游度假
-----------------------
张组长无法审批,转交给上级
李经理无法审批,转交给上级
王总监无法审批,转交给上级
陈总(CEO)审批通过 - 重要记录备案
员工:赵六
天数:10天
原因:婚假
审批时间:Tue Oct 10 14:30:00 CST 2023
-----------------------

=== 动态修改责任链(跳过总监) ===
张组长无法审批,转交给上级
李经理无法审批,转交给上级
陈总(CEO)审批通过 - 重要记录备案
员工:孙七
天数:6天
原因:病假
审批时间:Tue Oct 10 14:30:05 CST 2023
-----------------------

5. 责任链模式的变体

5.1 纯的责任链 vs 不纯的责任链

纯的责任链:一个请求必须被某个处理者处理,不能出现无处理者的情况。

java 复制代码
public abstract class PureApprover {
    protected PureApprover nextApprover;
    
    // 纯责任链:必须处理请求,不能传递
    public abstract void handleRequest(LeaveRequest request);
}

不纯的责任链:允许请求不被处理,或者被多个处理者处理。

java 复制代码
public abstract class ImpureApprover {
    protected ImpureApprover nextApprover;
    
    // 不纯责任链:可以选择处理或传递
    public void handleRequest(LeaveRequest request) {
        // 1. 自己先处理一部分
        doSomething(request);
        
        // 2. 传递给下一个(可选)
        if (nextApprover != null && canPass(request)) {
            nextApprover.handleRequest(request);
        }
    }
    
    protected abstract void doSomething(LeaveRequest request);
    protected abstract boolean canPass(LeaveRequest request);
}

5.2 使用链式调用构建责任链

java 复制代码
/**
 * 使用链式调用构建责任链
 */
public class ChainBuilder {
    public static void main(String[] args) {
        // 链式构建责任链
        Approver chain = new GroupLeader("组长")
            .setNextApprover(new Manager("经理"))
            .setNextApprover(new Director("总监"))
            .setNextApprover(new CEO("CEO"));
        
        // 使用构建好的链
        LeaveRequest request = new LeaveRequest("员工", 4, "事假");
        chain.processRequest(request);
    }
}

5.3 使用集合管理责任链

java 复制代码
/**
 * 使用集合管理多个处理者
 */
public class ApproverChain {
    private List<Approver> approvers = new ArrayList<>();
    private int index = 0;
    
    public void addApprover(Approver approver) {
        approvers.add(approver);
    }
    
    public void processRequest(LeaveRequest request) {
        if (index < approvers.size()) {
            Approver approver = approvers.get(index);
            index++;
            
            if (request.getDays() <= approver.getMaxDays()) {
                approver.processRequest(request);
            } else {
                processRequest(request);  // 递归调用下一个
            }
        } else {
            System.out.println("无人能够审批该请求");
        }
    }
    
    public void reset() {
        index = 0;
    }
}

6. 责任链模式的优势

6.1 对比原始实现

对比维度 原始实现(if-else) 责任链模式
新增审批级别 需要修改原有代码 只需新增一个处理者类
调整审批顺序 需要修改代码逻辑 只需调整链的顺序
代码结构 一个方法包含所有逻辑 逻辑分散到各个处理者
可测试性 难以单独测试每种情况 每个处理者可独立测试
遵循原则 违反开闭原则 符合开闭原则、单一职责原则

6.2 核心优势

  1. 降低耦合度:请求发送者不需要知道具体哪个对象处理请求
  2. 增强灵活性:可以动态地增加、删除或重新排列处理者
  3. 简化对象职责:每个处理者只负责自己的处理逻辑
  4. 符合开闭原则:新增处理者不需要修改现有代码

7. 责任链模式的实际应用场景

场景1:过滤器链(如Servlet Filter)

java 复制代码
// 模拟Servlet Filter的责任链
public interface Filter {
    void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain);
}

public class FilterChain {
    private List<Filter> filters = new ArrayList<>();
    private int index = 0;
    
    public void addFilter(Filter filter) {
        filters.add(filter);
    }
    
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        if (index < filters.size()) {
            Filter filter = filters.get(index);
            index++;
            filter.doFilter(request, response, this);
        }
    }
}

// 具体过滤器
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        System.out.println("日志过滤器:记录请求 " + request.getRequestURI());
        chain.doFilter(request, response);
        System.out.println("日志过滤器:记录响应");
    }
}

public class AuthFilter implements Filter {
    @Override
    public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        System.out.println("认证过滤器:检查用户登录状态");
        if (isAuthenticated(request)) {
            chain.doFilter(request, response);
        } else {
            response.setStatus(401);
        }
    }
    
    private boolean isAuthenticated(HttpServletRequest request) {
        // 检查认证逻辑
        return true;
    }
}

场景2:异常处理链

java 复制代码
// 异常处理责任链
public abstract class ExceptionHandler {
    protected ExceptionHandler nextHandler;
    
    public void setNextHandler(ExceptionHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    public void handle(Exception exception) {
        if (canHandle(exception)) {
            doHandle(exception);
        } else if (nextHandler != null) {
            nextHandler.handle(exception);
        } else {
            System.out.println("没有处理器能够处理该异常: " + exception.getClass().getName());
        }
    }
    
    protected abstract boolean canHandle(Exception exception);
    protected abstract void doHandle(Exception exception);
}

// 具体异常处理器
public class NullPointerExceptionHandler extends ExceptionHandler {
    @Override
    protected boolean canHandle(Exception exception) {
        return exception instanceof NullPointerException;
    }
    
    @Override
    protected void doHandle(Exception exception) {
        System.out.println("处理空指针异常: " + exception.getMessage());
        // 具体的处理逻辑...
    }
}

public class IOExceptionHandler extends ExceptionHandler {
    @Override
    protected boolean canHandle(Exception exception) {
        return exception instanceof IOException;
    }
    
    @Override
    protected void doHandle(Exception exception) {
        System.out.println("处理IO异常: " + exception.getMessage());
        // 具体的处理逻辑...
    }
}

8. Spring框架中的责任链模式

Spring框架中大量使用了责任链模式,最典型的就是Spring MVC的拦截器链:

java 复制代码
// Spring MVC拦截器接口(简化版)
public interface HandlerInterceptor {
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
    void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView);
    void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}

// Spring Security过滤器链
public class SecurityFilterChain {
    private List<Filter> filters;
    
    public void doFilter(HttpServletRequest request, HttpServletResponse response) {
        // 创建过滤器链并执行
        VirtualFilterChain chain = new VirtualFilterChain(request, filters);
        chain.doFilter(request, response);
    }
    
    private static class VirtualFilterChain {
        private final List<Filter> additionalFilters;
        private int currentPosition = 0;
        
        public void doFilter(HttpServletRequest request, HttpServletResponse response) {
            if (currentPosition == additionalFilters.size()) {
                // 所有过滤器执行完毕
                return;
            }
            
            Filter nextFilter = additionalFilters.get(currentPosition);
            currentPosition++;
            
            nextFilter.doFilter(request, response, this);
        }
    }
}

9. 责任链模式的最佳实践

9.1 使用建造者模式构建链

java 复制代码
/**
 * 使用建造者模式构建责任链
 */
public class ApproverChainBuilder {
    private Approver first;
    private Approver last;
    
    public ApproverChainBuilder addApprover(Approver approver) {
        if (first == null) {
            first = approver;
            last = approver;
        } else {
            last.setNextApprover(approver);
            last = approver;
        }
        return this;
    }
    
    public Approver build() {
        return first;
    }
    // ** 省略部分代码
}

// 使用方式
Approver chain = new ApproverChainBuilder()
    .addApprover(new GroupLeader("组长"))
    .addApprover(new Manager("经理"))
    .addApprover(new Director("总监"))
    .build();

9.2 处理链的终止条件

java 复制代码
/**
 * 改进的抽象处理者,支持终止链
 */
public abstract class ImprovedApprover {
    protected ImprovedApprover nextApprover;
    
    public void setNextApprover(ImprovedApprover nextApprover) {
        this.nextApprover = nextApprover;
    }
    
    public void processRequest(LeaveRequest request) {
        // 处理请求
        boolean handled = handle(request);
        
        // 如果当前处理者没有处理,并且有下一个处理者,则传递
        if (!handled && nextApprover != null) {
            nextApprover.processRequest(request);
        } else if (!handled) {
            // 链终止,没有处理者能够处理
            System.out.println("请求未被处理: " + request);
        }
    }
    
    /**
     * 处理请求,返回true表示已处理,false表示未处理
     */
    protected abstract boolean handle(LeaveRequest request);
}

10. 责任链模式的局限性

  1. 请求可能不被处理:如果链中没有合适的处理者,请求可能得不到处理
  2. 性能问题:链过长时,请求需要经过多个处理者,可能影响性能
  3. 调试困难:请求在链中传递,调试时难以跟踪具体经过哪些处理者
  4. 可能产生循环引用:如果链形成环,会导致死循环

11. 总结

责任链模式是一种非常实用的设计模式,它通过将多个处理者连接成一条链,让请求沿着链传递,直到被某个处理者处理。这种模式特别适合处理需要经过多个步骤或级别的场景。

责任链模式的核心价值

  • 解耦发送者和接收者:发送者不需要知道具体哪个对象处理请求
  • 动态配置处理流程:可以动态地增加、删除或调整处理者顺序
  • 提高代码可维护性:每个处理者只关注自己的职责,符合单一职责原则

使用责任链模式时要注意

  • 确保链不会过长,避免性能问题
  • 确保请求最终能够被处理,或者有合适的兜底处理
  • 注意避免循环引用导致的死循环
相关推荐
invicinble2 小时前
设计模式全局预览,以及为什么会
设计模式
小股虫3 小时前
让系统“杀不死”:同步与异步场景下的弹性设计模式手册
分布式·微服务·设计模式·架构·团队建设·方法论
山风wind4 小时前
设计模式:状态模式详解-让对象的行为随状态改变而改变
设计模式·状态模式
__万波__5 小时前
二十三种设计模式(十八)--中介者模式
java·设计模式·中介者模式
自由生长202412 小时前
设计模式和设计原则-中高级架构思路-面向接口编程
设计模式
大厂技术总监下海1 天前
为何顶尖科技公司都依赖它?解码 Protocol Buffers 背后的高性能、可演进设计模式
分布式·设计模式
EnzoRay1 天前
代理模式
设计模式
weixin_478433321 天前
iluwatar 设计模式
java·开发语言·设计模式
郝学胜-神的一滴1 天前
Python面向对象编程:解耦、多态与魔法艺术
java·开发语言·c++·python·设计模式·软件工程