行为型模式:责任链模式
什么是责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它将请求的发送者和接收者解耦,允许多个对象都有机会处理请求。这些对象连接成一条链,请求沿着链传递,直到有对象处理它为止。
责任链模式的核心思想是:将能够处理同一类请求的对象连成一条链,请求沿着这条链传递,直到链上的某个对象能够处理该请求。这样可以避免请求发送者与接收者之间的耦合关系。
责任链模式的结构
责任链模式包含以下主要角色:
- 处理者(Handler):定义一个处理请求的接口,通常包含对下一个处理者的引用
- 具体处理者(Concrete Handler):实现处理者接口,处理它负责的请求,可以访问下一个处理者
- 客户端(Client):创建处理链,并向链上的第一个处理者发送请求
责任链模式的基本实现
下面是责任链模式的基本Java实现:
// 请求类
class Request {private String type;private int amount;public Request(String type, int amount) {this.type = type;this.amount = amount;}public String getType() {return type;}public int getAmount() {return amount;}
}// 处理者接口
interface Handler {Handler setNext(Handler handler);String handle(Request request);
}// 抽象处理者类
abstract class AbstractHandler implements Handler {private Handler next;@Overridepublic Handler setNext(Handler handler) {this.next = handler;return handler; // 返回下一个处理者,支持链式调用}@Overridepublic String handle(Request request) {if (next != null) {return next.handle(request);}return "没有处理者可以处理该请求";}
}// 具体处理者:经理
class ManagerHandler extends AbstractHandler {@Overridepublic String handle(Request request) {if ("请假".equals(request.getType()) && request.getAmount() <= 3) {return "经理已批准请假申请";}// 不能处理,传递给下一个处理者return super.handle(request);}
}// 具体处理者:总监
class DirectorHandler extends AbstractHandler {@Overridepublic String handle(Request request) {if ("请假".equals(request.getType()) && request.getAmount() <= 7) {return "总监已批准请假申请";} else if ("经费".equals(request.getType()) && request.getAmount() <= 5000) {return "总监已批准经费申请";}// 不能处理,传递给下一个处理者return super.handle(request);}
}// 具体处理者:CEO
class CEOHandler extends AbstractHandler {@Overridepublic String handle(Request request) {if ("请假".equals(request.getType()) && request.getAmount() <= 14) {return "CEO已批准请假申请";} else if ("经费".equals(request.getType()) && request.getAmount() <= 50000) {return "CEO已批准经费申请";}// 不能处理,传递给下一个处理者return super.handle(request);}
}// 客户端代码
public class ChainOfResponsibilityDemo {public static void main(String[] args) {// 创建处理链Handler manager = new ManagerHandler();Handler director = new DirectorHandler();Handler ceo = new CEOHandler();// 设置责任链manager.setNext(director).setNext(ceo);// 创建请求Request request1 = new Request("请假", 2);Request request2 = new Request("请假", 5);Request request3 = new Request("请假", 10);Request request4 = new Request("请假", 20);Request request5 = new Request("经费", 4000);Request request6 = new Request("经费", 20000);Request request7 = new Request("经费", 100000);// 处理请求System.out.println(manager.handle(request1)); // 经理处理System.out.println(manager.handle(request2)); // 总监处理System.out.println(manager.handle(request3)); // CEO处理System.out.println(manager.handle(request4)); // 无人处理System.out.println(manager.handle(request5)); // 总监处理System.out.println(manager.handle(request6)); // CEO处理System.out.println(manager.handle(request7)); // 无人处理}
}
实际应用示例:日志记录器
下面通过一个日志记录系统来展示责任链模式的实际应用:
// 日志级别枚举
enum LogLevel {INFO(1), DEBUG(2), ERROR(3);private int level;LogLevel(int level) {this.level = level;}public int getLevel() {return level;}
}// 日志对象
class LogMessage {private LogLevel level;private String message;public LogMessage(LogLevel level, String message) {this.level = level;this.message = message;}public LogLevel getLevel() {return level;}public String getMessage() {return message;}
}// 抽象日志处理器
abstract class LoggerHandler {protected LogLevel level;protected LoggerHandler next;public LoggerHandler(LogLevel level) {this.level = level;}// 设置下一个处理者public LoggerHandler setNext(LoggerHandler next) {this.next = next;return next;}// 处理日志消息public void log(LogMessage logMessage) {if (logMessage.getLevel().getLevel() >= this.level.getLevel()) {writeLog(logMessage);}if (next != null) {next.log(logMessage);}}// 由具体子类实现的写日志方法protected abstract void writeLog(LogMessage logMessage);
}// 控制台日志处理器
class ConsoleLogger extends LoggerHandler {public ConsoleLogger(LogLevel level) {super(level);}@Overrideprotected void writeLog(LogMessage logMessage) {System.out.println("控制台日志:" + logMessage.getLevel() + " - " + logMessage.getMessage());}
}// 文件日志处理器
class FileLogger extends LoggerHandler {public FileLogger(LogLevel level) {super(level);}@Overrideprotected void writeLog(LogMessage logMessage) {System.out.println("文件日志:" + logMessage.getLevel() + " - " + logMessage.getMessage());}
}// 数据库日志处理器
class DatabaseLogger extends LoggerHandler {public DatabaseLogger(LogLevel level) {super(level);}@Overrideprotected void writeLog(LogMessage logMessage) {System.out.println("数据库日志:" + logMessage.getLevel() + " - " + logMessage.getMessage());}
}// 客户端代码
public class LoggerExample {public static void main(String[] args) {// 创建日志处理链LoggerHandler consoleLogger = new ConsoleLogger(LogLevel.INFO);LoggerHandler fileLogger = new FileLogger(LogLevel.DEBUG);LoggerHandler databaseLogger = new DatabaseLogger(LogLevel.ERROR);// 构建责任链consoleLogger.setNext(fileLogger).setNext(databaseLogger);// 创建日志消息LogMessage infoLog = new LogMessage(LogLevel.INFO, "这是一条信息日志");LogMessage debugLog = new LogMessage(LogLevel.DEBUG, "这是一条调试日志");LogMessage errorLog = new LogMessage(LogLevel.ERROR, "这是一条错误日志");// 处理日志System.out.println("=== 处理信息日志 ===");consoleLogger.log(infoLog);System.out.println("\n=== 处理调试日志 ===");consoleLogger.log(debugLog);System.out.println("\n=== 处理错误日志 ===");consoleLogger.log(errorLog);}
}
实际应用示例:Web请求过滤器
下面是一个Web请求过滤器的例子,类似于Java Servlet Filter:
// HTTP请求
class HttpRequest {private String requestBody;private Map<String, String> headers;private String ip;public HttpRequest(String ip, Map<String, String> headers, String requestBody) {this.ip = ip;this.headers = headers;this.requestBody = requestBody;}public String getRequestBody() {return requestBody;}public Map<String, String> getHeaders() {return headers;}public String getIp() {return ip;}
}// HTTP响应
class HttpResponse {private int statusCode;private String body;public HttpResponse() {this.statusCode = 200;this.body = "";}public void setStatusCode(int statusCode) {this.statusCode = statusCode;}public void setBody(String body) {this.body = body;}@Overridepublic String toString() {return "HttpResponse{" +"statusCode=" + statusCode +", body='" + body + '\'' +'}';}
}// 过滤器接口
interface Filter {void setNext(Filter filter);HttpResponse doFilter(HttpRequest request, HttpResponse response);
}// 抽象过滤器
abstract class BaseFilter implements Filter {protected Filter next;@Overridepublic void setNext(Filter filter) {this.next = filter;}@Overridepublic HttpResponse doFilter(HttpRequest request, HttpResponse response) {// 如果有下一个过滤器,调用它if (next != null) {return next.doFilter(request, response);}return response;}
}// IP黑名单过滤器
class IpBlacklistFilter extends BaseFilter {private List<String> blacklist = Arrays.asList("192.168.1.1", "10.0.0.1");@Overridepublic HttpResponse doFilter(HttpRequest request, HttpResponse response) {if (blacklist.contains(request.getIp())) {response.setStatusCode(403);response.setBody("IP被禁止访问");return response;}return super.doFilter(request, response);}
}// 认证过滤器
class AuthenticationFilter extends BaseFilter {@Overridepublic HttpResponse doFilter(HttpRequest request, HttpResponse response) {if (!request.getHeaders().containsKey("Authorization")) {response.setStatusCode(401);response.setBody("需要认证");return response;}return super.doFilter(request, response);}
}// 内容类型过滤器
class ContentTypeFilter extends BaseFilter {@Overridepublic HttpResponse doFilter(HttpRequest request, HttpResponse response) {if (!request.getHeaders().containsKey("Content-Type") || !request.getHeaders().get("Content-Type").equals("application/json")) {response.setStatusCode(415);response.setBody("不支持的媒体类型");return response;}return super.doFilter(request, response);}
}// 日志过滤器
class LoggingFilter extends BaseFilter {@Overridepublic HttpResponse doFilter(HttpRequest request, HttpResponse response) {System.out.println("请求IP: " + request.getIp());System.out.println("请求头: " + request.getHeaders());HttpResponse processedResponse = super.doFilter(request, response);System.out.println("响应状态码: " + processedResponse.toString());return processedResponse;}
}// Web应用
class WebApplication {private Filter filterChain;public WebApplication(Filter filterChain) {this.filterChain = filterChain;}public HttpResponse handleRequest(HttpRequest request) {HttpResponse response = new HttpResponse();// 执行过滤器链response = filterChain.doFilter(request, response);// 如果请求通过所有过滤器,设置成功响应if (response.toString().contains("statusCode=200")) {response.setBody("请求处理成功");}return response;}
}// 客户端代码
public class WebFilterExample {public static void main(String[] args) {// 创建过滤器Filter loggingFilter = new LoggingFilter();Filter ipFilter = new IpBlacklistFilter();Filter authFilter = new AuthenticationFilter();Filter contentTypeFilter = new ContentTypeFilter();// 设置过滤器链loggingFilter.setNext(ipFilter);ipFilter.setNext(authFilter);authFilter.setNext(contentTypeFilter);// 创建Web应用WebApplication app = new WebApplication(loggingFilter);// 测试不同请求Map<String, String> headers1 = new HashMap<>();HttpRequest request1 = new HttpRequest("192.168.1.1", headers1, "");Map<String, String> headers2 = new HashMap<>();HttpRequest request2 = new HttpRequest("192.168.1.2", headers2, "");Map<String, String> headers3 = new HashMap<>();headers3.put("Authorization", "Bearer token123");HttpRequest request3 = new HttpRequest("192.168.1.2", headers3, "");Map<String, String> headers4 = new HashMap<>();headers4.put("Authorization", "Bearer token123");headers4.put("Content-Type", "application/json");HttpRequest request4 = new HttpRequest("192.168.1.2", headers4, "{\"key\":\"value\"}");// 处理请求System.out.println("=== 请求1: 黑名单IP ===");System.out.println(app.handleRequest(request1));System.out.println("\n=== 请求2: 未认证 ===");System.out.println(app.handleRequest(request2));System.out.println("\n=== 请求3: 缺少Content-Type ===");System.out.println(app.handleRequest(request3));System.out.println("\n=== 请求4: 有效请求 ===");System.out.println(app.handleRequest(request4));}
}
责任链模式在Java API中的应用
Java API中有多个使用责任链模式的例子:
-
java.util.logging.Logger:日志记录器采用了责任链模式,消息沿着Logger层次结构传递。
-
javax.servlet.Filter:Java Servlet中的过滤器链,HTTP请求依次经过一系列过滤器处理。
-
java.awt.Container#dispatchEvent():事件处理中,事件沿着组件层次结构传递。
责任链模式的优点
-
降低耦合度:请求发送者与接收者解耦,发送者无需知道谁会处理请求。
-
增强灵活性:可以动态地添加、删除或重新排序处理者,而不影响客户端代码。
-
符合单一职责原则:每个处理者只关注自己能处理的请求类型。
-
符合开闭原则:无需修改现有代码即可添加新的处理者。
-
可以实现不同的处理方式:请求可以由一个处理者处理或多个处理者部分处理。
责任链模式的缺点
-
请求可能没有处理者:如果链末尾没有合适的处理者,请求可能未被处理。
-
性能问题:请求可能要遍历整条链才能找到合适的处理者。
-
调试困难:请求在链中的行为路径不易跟踪,增加了调试难度。
-
可能的递归调用:处理者之间的递归调用可能导致栈溢出。
责任链模式与其他模式的比较
责任链 vs 命令模式
- 责任链模式:专注于请求的传递和处理,接收者可能有多个。
- 命令模式:将请求封装为对象,关注请求的发送者和接收者之间的解耦。
责任链 vs 装饰器模式
- 责任链模式:每个处理者决定是否处理请求或传递给下一个处理者。
- 装饰器模式:每个装饰器都会处理请求,然后将其传递给下一个组件。
责任链模式的变体
1. 纯责任链
每个处理者要么完全处理请求,要么将请求完全传递给下一个处理者:
// 纯责任链处理者
interface PureHandler {boolean handle(Request request);void setNext(PureHandler handler);
}
2. 带回调的责任链
处理完成后调用回调方法:
// 带回调的处理者
interface CallbackHandler {void handle(Request request, Callback callback);
}// 回调接口
interface Callback {void onSuccess(String result);void onFailure(String error);
}
最佳实践和注意事项
-
合理设置处理顺序:将常用或简单的处理者放在链的前面,提高效率。
-
设置默认处理者:确保链末尾有默认处理者,避免请求未处理。
-
警惕处理循环:确保责任链中不会出现循环引用。
-
避免过长的责任链:过长的链会影响性能和可维护性。
-
考虑链的动态性:在某些情况下,可能需要动态修改责任链。
-
明确终止条件:每个处理者应明确何时停止处理,何时传递请求。
总结
责任链模式是一种强大的行为设计模式,它允许多个对象处理同一个请求,而发送者无需知道具体的处理者。通过将对象连成一条链,并沿着链传递请求,直到有对象能够处理它为止,责任链模式提供了一种灵活且松耦合的解决方案。
这种模式在需要按特定顺序处理请求,或者不确定由哪个对象处理请求的场景中非常有用。它广泛应用于日志记录、错误处理、请求过滤、事件处理等多种场景。
虽然责任链模式有可能导致请求未被处理或性能问题,但通过合理设计和使用,这些缺点是可以避免的。在复杂的系统中,责任链模式是实现灵活处理流程的有效工具。