模式定义

责任链模式是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。责任链模式解耦了发送者和接收者,发送者不需要知道具体是哪个接收者处理请求。

模式结构

graph TD A[Client] --> B[Handler] B --> C[ConcreteHandler1] B --> D[ConcreteHandler2] B --> E[ConcreteHandler3] C --> D D --> E

实现方式

基础实现

定义处理者接口,实现具体处理者类。

// 处理者抽象类
public abstract class Logger {
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;
    
    protected int level;
    
    // 责任链中的下一个处理者
    protected Logger nextLogger;
    
    public void setNextLogger(Logger nextLogger) {
        this.nextLogger = nextLogger;
    }
    
    public void logMessage(int level, String message) {
        if (this.level <= level) {
            write(message);
        }
        if (nextLogger != null) {
            nextLogger.logMessage(level, message);
        }
    }
    
    abstract protected void write(String message);
}

// 具体处理者 - 控制台日志记录器
class ConsoleLogger extends Logger {
    public ConsoleLogger(int level) {
        this.level = level;
    }
    
    @Override
    protected void write(String message) {
        System.out.println("标准控制台::Logger: " + message);
    }
}

// 具体处理者 - 错误日志记录器
class ErrorLogger extends Logger {
    public ErrorLogger(int level) {
        this.level = level;
    }
    
    @Override
    protected void write(String message) {
        System.out.println("错误控制台::Logger: " + message);
    }
}

// 具体处理者 - 文件日志记录器
class FileLogger extends Logger {
    public FileLogger(int level) {
        this.level = level;
    }
    
    @Override
    protected void write(String message) {
        System.out.println("文件::Logger: " + message);
    }
}

使用示例

public class ChainPatternDemo {
    private static Logger getChainOfLoggers() {
        Logger errorLogger = new ErrorLogger(Logger.ERROR);
        Logger fileLogger = new FileLogger(Logger.DEBUG);
        Logger consoleLogger = new ConsoleLogger(Logger.INFO);
        
        errorLogger.setNextLogger(fileLogger);
        fileLogger.setNextLogger(consoleLogger);
        
        return errorLogger;
    }
    
    public static void main(String[] args) {
        Logger loggerChain = getChainOfLoggers();
        
        System.out.println("---------INFO级别日志---------");
        loggerChain.logMessage(Logger.INFO, "这是信息级别的日志");
        
        System.out.println("\n---------DEBUG级别日志---------");
        loggerChain.logMessage(Logger.DEBUG, "这是调试级别的日志");
        
        System.out.println("\n---------ERROR级别日志---------");
        loggerChain.logMessage(Logger.ERROR, "这是错误级别的日志");
    }
}

经典案例

1. Java Servlet过滤器

Java Servlet中的Filter就是责任链模式的典型应用:

// 过滤器接口
public interface Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException;
}

// 具体过滤器 - 认证过滤器
public class AuthenticationFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        // 检查用户是否已认证
        HttpServletRequest req = (HttpServletRequest) request;
        String userAgent = req.getHeader("User-Agent");
        
        System.out.println("认证过滤器: " + userAgent);
        
        // 如果认证通过,继续执行下一个过滤器
        chain.doFilter(request, response);
    }
}

// 具体过滤器 - 调试过滤器
public class DebugFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest req = (HttpServletRequest) request;
        String requestURI = req.getRequestURI();
        
        System.out.println("调试过滤器: " + requestURI);
        
        // 继续执行下一个过滤器
        chain.doFilter(request, response);
    }
}

// 过滤器链
public class FilterChain {
    private List filters = new ArrayList<>();
    private int index = 0;
    
    public void addFilter(Filter filter) {
        filters.add(filter);
    }
    
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
        if (index < filters.size()) {
            Filter filter = filters.get(index++);
            filter.doFilter(request, response, this);
        }
        // 如果所有过滤器都执行完毕,调用目标资源
        else {
            // 调用目标Servlet
        }
    }
}

2. ATM取款机

ATM取款机的纸币分发机制也是责任链模式的应用:

// 抽象处理者
public abstract class CashHandler {
    protected CashHandler nextHandler;
    protected int denomination;
    
    public void setNextHandler(CashHandler nextHandler) {
        this.nextHandler = nextHandler;
    }
    
    public void dispense(int amount) {
        if (amount >= denomination) {
            int count = amount / denomination;
            int remainder = amount % denomination;
            System.out.println("分发 " + count + " 张 " + denomination + " 元钞票");
            
            if (remainder != 0 && nextHandler != null) {
                nextHandler.dispense(remainder);
            }
        } else if (nextHandler != null) {
            nextHandler.dispense(amount);
        }
    }
}

// 具体处理者 - 100元钞票处理器
class HundredDollarHandler extends CashHandler {
    public HundredDollarHandler() {
        this.denomination = 100;
    }
}

// 具体处理者 - 50元钞票处理器
class FiftyDollarHandler extends CashHandler {
    public FiftyDollarHandler() {
        this.denomination = 50;
    }
}

// 具体处理者 - 20元钞票处理器
class TwentyDollarHandler extends CashHandler {
    public TwentyDollarHandler() {
        this.denomination = 20;
    }
}

// ATM类
public class ATM {
    private CashHandler hundredHandler;
    private CashHandler fiftyHandler;
    private CashHandler twentyHandler;
    
    public ATM() {
        // 构建责任链
        hundredHandler = new HundredDollarHandler();
        fiftyHandler = new FiftyDollarHandler();
        twentyHandler = new TwentyDollarHandler();
        
        hundredHandler.setNextHandler(fiftyHandler);
        fiftyHandler.setNextHandler(twentyHandler);
    }
    
    public void dispense(int amount) {
        if (amount % 10 != 0) {
            System.out.println("金额必须是10的倍数");
            return;
        }
        hundredHandler.dispense(amount);
    }
}

// 使用示例
public class ATMDemo {
    public static void main(String[] args) {
        ATM atm = new ATM();
        
        System.out.println("取出 230 元:");
        atm.dispense(230);
        
        System.out.println("\n取出 180 元:");
        atm.dispense(180);
        
        System.out.println("\n取出 55 元:");
        atm.dispense(55);
    }
}

应用场景

优缺点

优点

  • 降低耦合度:发送者和接收者之间解耦,发送者不需要知道具体是哪个接收者处理请求
  • 增强灵活性:可以动态地增加或删除处理者,改变处理者之间的先后顺序
  • 简化对象:处理者只需保持一个指向其后继者的引用,不需要知道所有处理者
  • 符合开闭原则:增加新的具体处理者无需修改现有代码

缺点

  • 不能保证请求一定被处理:可能到最后都没有处理者处理请求
  • 性能问题:请求可能需要遍历整个链才能处理
  • 调试困难:由于处理链较长,调试时可能比较困难
  • 可能造成循环调用:如果链中存在循环引用,可能导致系统崩溃