责任链模式
基础概念
什么是责任链模式?
答案: 责任链模式(Chain of Responsibility Pattern)为请求创建一个接收者对象的链,每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把请求传给下一个接收者。
使用场景:
- 多个对象可以处理同一请求
- 不明确指定接收者
- 动态指定处理者集合
优点:
- 降低耦合度
- 增强灵活性
- 简化对象
缺点:
- 请求可能不被处理
- 性能影响
- 调试困难
实现方式
基本实现?
答案:
java
// 抽象处理者
public abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(int level);
}
// 具体处理者A
public class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(int level) {
if (level <= 1) {
System.out.println("处理者A处理请求");
} else if (nextHandler != null) {
nextHandler.handleRequest(level);
}
}
}
// 具体处理者B
public class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(int level) {
if (level <= 2) {
System.out.println("处理者B处理请求");
} else if (nextHandler != null) {
nextHandler.handleRequest(level);
}
}
}
// 具体处理者C
public class ConcreteHandlerC extends Handler {
@Override
public void handleRequest(int level) {
if (level <= 3) {
System.out.println("处理者C处理请求");
} else {
System.out.println("无法处理");
}
}
}
// 使用
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setNextHandler(handlerB);
handlerB.setNextHandler(handlerC);
handlerA.handleRequest(1); // A处理
handlerA.handleRequest(2); // B处理
handlerA.handleRequest(3); // C处理实际应用
请假审批
答案:
java
// 请假请求
public class LeaveRequest {
private String name;
private int days;
public LeaveRequest(String name, int days) {
this.name = name;
this.days = days;
}
public String getName() {
return name;
}
public int getDays() {
return days;
}
}
// 抽象审批者
public abstract class Approver {
protected Approver nextApprover;
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void approve(LeaveRequest request);
}
// 组长(1天以内)
public class TeamLeader extends Approver {
@Override
public void approve(LeaveRequest request) {
if (request.getDays() <= 1) {
System.out.println("组长批准" + request.getName() + "请假" + request.getDays() + "天");
} else if (nextApprover != null) {
nextApprover.approve(request);
}
}
}
// 经理(3天以内)
public class Manager extends Approver {
@Override
public void approve(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("经理批准" + request.getName() + "请假" + request.getDays() + "天");
} else if (nextApprover != null) {
nextApprover.approve(request);
}
}
}
// 总监(7天以内)
public class Director extends Approver {
@Override
public void approve(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("总监批准" + request.getName() + "请假" + request.getDays() + "天");
} else {
System.out.println("请假天数过多,拒绝");
}
}
}
// 使用
Approver teamLeader = new TeamLeader();
Approver manager = new Manager();
Approver director = new Director();
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
teamLeader.approve(new LeaveRequest("张三", 1)); // 组长批准
teamLeader.approve(new LeaveRequest("李四", 3)); // 经理批准
teamLeader.approve(new LeaveRequest("王五", 7)); // 总监批准日志处理
答案:
java
// 日志级别
public enum LogLevel {
DEBUG, INFO, WARN, ERROR
}
// 抽象日志处理器
public abstract class LogHandler {
protected LogLevel level;
protected LogHandler nextHandler;
public LogHandler(LogLevel level) {
this.level = level;
}
public void setNextHandler(LogHandler nextHandler) {
this.nextHandler = nextHandler;
}
public void log(LogLevel level, String message) {
if (this.level.ordinal() <= level.ordinal()) {
write(message);
}
if (nextHandler != null) {
nextHandler.log(level, message);
}
}
protected abstract void write(String message);
}
// 控制台日志处理器
public class ConsoleLogHandler extends LogHandler {
public ConsoleLogHandler(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("Console: " + message);
}
}
// 文件日志处理器
public class FileLogHandler extends LogHandler {
public FileLogHandler(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("File: " + message);
}
}
// 邮件日志处理器
public class EmailLogHandler extends LogHandler {
public EmailLogHandler(LogLevel level) {
super(level);
}
@Override
protected void write(String message) {
System.out.println("Email: " + message);
}
}
// 使用
LogHandler consoleHandler = new ConsoleLogHandler(LogLevel.DEBUG);
LogHandler fileHandler = new FileLogHandler(LogLevel.WARN);
LogHandler emailHandler = new EmailLogHandler(LogLevel.ERROR);
consoleHandler.setNextHandler(fileHandler);
fileHandler.setNextHandler(emailHandler);
consoleHandler.log(LogLevel.DEBUG, "调试信息"); // 只有Console输出
consoleHandler.log(LogLevel.WARN, "警告信息"); // Console和File输出
consoleHandler.log(LogLevel.ERROR, "错误信息"); // 全部输出Servlet Filter
Filter责任链?
答案:
java
// Filter接口
public interface Filter {
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
}
// 编码过滤器
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response); // 传递给下一个过滤器
}
}
// 认证过滤器
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
String token = request.getParameter("token");
if (token != null) {
chain.doFilter(request, response);
} else {
response.getWriter().write("未授权");
}
}
}
// 日志过滤器
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
System.out.println("请求开始");
chain.doFilter(request, response);
System.out.println("请求结束");
}
}Spring中的责任链
Spring Interceptor?
答案:
java
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);
}
// 自定义拦截器
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (token != null) {
return true; // 继续执行
}
response.setStatus(401);
return false; // 中断执行
}
}
// 配置拦截器链
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}练习题
- 责任链模式和装饰器模式的区别?
- 如何避免责任链过长?
- 责任链模式如何保证请求一定被处理?
- Servlet Filter和Spring Interceptor的区别?
- 如何实现可配置的责任链?