责任链模式 (Chain of Responsibility Pattern)
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系
模式定义
责任链模式是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。责任链模式解耦了发送者和接收者,发送者不需要知道具体是哪个接收者处理请求。
模式结构
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);
}
}
应用场景
- 多个对象可以处理同一个请求,但具体由哪个对象处理在运行时确定
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
- 可动态指定一组对象处理请求,客户端可以动态创建职责链
- 日志处理系统:根据日志级别将日志分发给不同的处理器
- 异常处理机制:不同级别的异常由不同的处理器处理
- 审批流程:不同级别的审批由不同的管理者处理
- 过滤器链:Web应用中的请求过滤处理
优缺点
优点
- 降低耦合度:发送者和接收者之间解耦,发送者不需要知道具体是哪个接收者处理请求
- 增强灵活性:可以动态地增加或删除处理者,改变处理者之间的先后顺序
- 简化对象:处理者只需保持一个指向其后继者的引用,不需要知道所有处理者
- 符合开闭原则:增加新的具体处理者无需修改现有代码
缺点
- 不能保证请求一定被处理:可能到最后都没有处理者处理请求
- 性能问题:请求可能需要遍历整个链才能处理
- 调试困难:由于处理链较长,调试时可能比较困难
- 可能造成循环调用:如果链中存在循环引用,可能导致系统崩溃