文章目录
1. 责任链模式概述
1.1 定义
责任链模式是一种行为型设计模式,它将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
1.2 基本思想
责任链模式的核心思想是:
- 将能够处理同一类请求的对象连成一条链
- 请求沿着链传递,直到有一个对象处理它
- 客户端不需要知道是哪个对象处理了请求
2. 责任链模式的结构
责任链模式包含以下角色:
- 抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接
- 具体处理者(ConcreteHandler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以则处理,否则将请求转给后继者
- 客户端(Client):创建责任链,并向链上的具体处理者对象提交请求
3. 责任链模式的UML类图
┌───────────────┐ ┌─────────────────┐
│ Client │─────────>│ <<interface>> │
└───────────────┘ │ Handler │
├─────────────────┤
│ +successor │
│ +handleRequest()│
└────────┬────────┘
│
│
┌─────────────────────┼─────────────────────┐
│ │ │
┌────────────▼───────────┐ ┌──────▼───────────────┐ ┌───▼────────────────────┐
│ ConcreteHandler1 │ │ ConcreteHandler2 │ │ ConcreteHandler3 │
├────────────────────────┤ ├──────────────────────┤ ├──────────────────────────┤
│ +handleRequest() │ │ +handleRequest() │ │ +handleRequest() │
└────────────────────────┘ └──────────────────────┘ └──────────────────────────┘
4. 责任链模式的工作原理
- 客户端创建各个处理者对象,并组装成一条链
- 客户端将请求发送给链中的第一个处理者
- 处理者对象判断是否能处理该请求:
- 如果能处理,则处理该请求
- 如果不能处理,则将请求转发给下一个处理者
- 重复步骤3,直到有一个处理者处理请求或者链结束
5. Java实现示例
5.1 基本实现示例
下面是一个简单的责任链模式实现示例,假设我们有一个请假审批系统:
// 抽象处理者
abstract class LeaveHandler {
protected LeaveHandler nextHandler; // 后继处理者
// 设置后继者
public void setNextHandler(LeaveHandler nextHandler) {
this.nextHandler = nextHandler;
}
// 处理请求的抽象方法
public abstract void handleRequest(int leaveDays);
}
// 具体处理者:主管
class DirectorHandler extends LeaveHandler {
@Override
public void handleRequest(int leaveDays) {
if (leaveDays <= 3) { // 主管可以批准3天以内的假期
System.out.println("主管批准了" + leaveDays + "天的请假申请");
} else if (nextHandler != null) {
System.out.println("主管无权批准,转交给经理");
nextHandler.handleRequest(leaveDays);
} else {
System.out.println("请假申请未被批准");
}
}
}
// 具体处理者:经理
class ManagerHandler extends LeaveHandler {
@Override
public void handleRequest(int leaveDays) {
if (leaveDays <= 7) { // 经理可以批准7天以内的假期
System.out.println("经理批准了" + leaveDays + "天的请假申请");
} else if (nextHandler != null) {
System.out.println("经理无权批准,转交给总监");
nextHandler.handleRequest(leaveDays);
} else {
System.out.println("请假申请未被批准");
}
}
}
// 具体处理者:总监
class DirectorOfDeptHandler extends LeaveHandler {
@Override
public void handleRequest(int leaveDays) {
if (leaveDays <= 15) { // 总监可以批准15天以内的假期
System.out.println("总监批准了" + leaveDays + "天的请假申请");
} else if (nextHandler != null) {
System.out.println("总监无权批准,转交给CEO");
nextHandler.handleRequest(leaveDays);
} else {
System.out.println("请假申请未被批准");
}
}
}
// 具体处理者:CEO
class CEOHandler extends LeaveHandler {
@Override
public void handleRequest(int leaveDays) {
if (leaveDays <= 30) { // CEO可以批准30天以内的假期
System.out.println("CEO批准了" + leaveDays + "天的请假申请");
} else {
System.out.println("CEO拒绝了" + leaveDays + "天的请假申请,时间太长了!");
}
}
}
// 客户端
public class LeaveApprovalDemo {
public static void main(String[] args) {
// 创建各个处理者对象
LeaveHandler director = new DirectorHandler();
LeaveHandler manager = new ManagerHandler();
LeaveHandler directorOfDept = new DirectorOfDeptHandler();
LeaveHandler ceo = new CEOHandler();
// 组装责任链
director.setNextHandler(manager);
manager.setNextHandler(directorOfDept);
directorOfDept.setNextHandler(ceo);
// 提交请求
System.out.println("-----请假3天-----");
director.handleRequest(3);
System.out.println("-----请假5天-----");
director.handleRequest(5);
System.out.println("-----请假15天-----");
director.handleRequest(15);
System.out.println("-----请假25天-----");
director.handleRequest(25);
System.out.println("-----请假35天-----");
director.handleRequest(35);
}
}
5.2 使用接口实现责任链模式
// 抽象处理者接口
interface Handler {
void setNext(Handler handler);
Handler getNext();
void handleRequest(Request request);
}
// 抽象处理者类
abstract class AbstractHandler implements Handler {
private Handler next;
@Override
public void setNext(Handler handler) {
this.next = handler;
}
@Override
public Handler getNext() {
return next;
}
// 模板方法,定义责任链的处理逻辑
@Override
public void handleRequest(Request request) {
if (canHandle(request)) {
processRequest(request);
} else if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有处理者能处理该请求");
}
}
// 判断是否能处理请求
protected abstract boolean canHandle(Request request);
// 处理请求
protected abstract void processRequest(Request request);
}
// 请求类
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;
}
}
// 具体处理者类:小额采购
class SmallPurchaseHandler extends AbstractHandler {
@Override
protected boolean canHandle(Request request) {
return "purchase".equals(request.getType()) && request.getAmount() <= 5000;
}
@Override
protected void processRequest(Request request) {
System.out.println("部门主管处理采购请求,金额:" + request.getAmount());
}
}
// 具体处理者类:中额采购
class MediumPurchaseHandler extends AbstractHandler {
@Override
protected boolean canHandle(Request request) {
return "purchase".equals(request.getType()) && request.getAmount() <= 20000;
}
@Override
protected void processRequest(Request request) {
System.out.println("采购部经理处理采购请求,金额:" + request.getAmount());
}
}
// 具体处理者类:大额采购
class LargePurchaseHandler extends AbstractHandler {
@Override
protected boolean canHandle(Request request) {
return "purchase".equals(request.getType()) && request.getAmount() <= 100000;
}
@Override
protected void processRequest(Request request) {
System.out.println("公司副总裁处理采购请求,金额:" + request.getAmount());
}
}
// 具体处理者类:超大额采购
class HugePurchaseHandler extends AbstractHandler {
@Override
protected boolean canHandle(Request request) {
return "purchase".equals(request.getType());
}
@Override
protected void processRequest(Request request) {
System.out.println("董事会处理采购请求,金额:" + request.getAmount());
}
}
// 客户端
public class PurchaseDemo {
public static void main(String[] args) {
// 创建处理者
Handler smallPurchaseHandler = new SmallPurchaseHandler();
Handler mediumPurchaseHandler = new MediumPurchaseHandler();
Handler largePurchaseHandler = new LargePurchaseHandler();
Handler hugePurchaseHandler = new HugePurchaseHandler();
// 组装责任链
smallPurchaseHandler.setNext(mediumPurchaseHandler);
mediumPurchaseHandler.setNext(largePurchaseHandler);
largePurchaseHandler.setNext(hugePurchaseHandler);
// 创建请求并发送
Request request1 = new Request("purchase", 4000);
Request request2 = new Request("purchase", 15000);
Request request3 = new Request("purchase", 80000);
Request request4 = new Request("purchase", 300000);
smallPurchaseHandler.handleRequest(request1);
smallPurchaseHandler.handleRequest(request2);
smallPurchaseHandler.handleRequest(request3);
smallPurchaseHandler.handleRequest(request4);
}
}
5.3 责任链模式在日志系统中的应用
// 日志级别枚举
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 nextLogger;
public LoggerHandler(LogLevel level) {
this.level = level;
}
public void setNextLogger(LoggerHandler nextLogger) {
this.nextLogger = nextLogger;
}
public void logMessage(LogMessage logMessage) {
if (logMessage.getLevel().getLevel() >= this.level.getLevel()) {
write(logMessage);
}
if (nextLogger != null) {
nextLogger.logMessage(logMessage);
}
}
protected abstract void write(LogMessage logMessage);
}
// 控制台日志处理者
class ConsoleLogger extends LoggerHandler {
public ConsoleLogger(LogLevel level) {
super(level);
}
@Override
protected void write(LogMessage logMessage) {
System.out.println("控制台日志: " + logMessage.getMessage());
}
}
// 文件日志处理者
class FileLogger extends LoggerHandler {
public FileLogger(LogLevel level) {
super(level);
}
@Override
protected void write(LogMessage logMessage) {
System.out.println("文件日志: " + logMessage.getMessage());
}
}
// 数据库日志处理者
class DatabaseLogger extends LoggerHandler {
public DatabaseLogger(LogLevel level) {
super(level);
}
@Override
protected void write(LogMessage logMessage) {
System.out.println("数据库日志: " + logMessage.getMessage());
}
}
// 客户端
public class LoggerChainDemo {
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.setNextLogger(fileLogger);
fileLogger.setNextLogger(databaseLogger);
// 处理日志
LogMessage infoLog = new LogMessage(LogLevel.INFO, "这是一条普通信息");
LogMessage debugLog = new LogMessage(LogLevel.DEBUG, "这是一条调试信息");
LogMessage errorLog = new LogMessage(LogLevel.ERROR, "这是一条错误信息");
System.out.println("-----Info日志处理-----");
consoleLogger.logMessage(infoLog);
System.out.println("-----Debug日志处理-----");
consoleLogger.logMessage(debugLog);
System.out.println("-----Error日志处理-----");
consoleLogger.logMessage(errorLog);
}
}
6. 责任链模式的优缺点
6.1 优点
- 降低耦合度:将请求的发送者和接收者解耦,发送者无需知道请求被谁处理
- 增强了给对象指派职责的灵活性:通过改变链内的成员或调整它们的次序,允许动态地新增或删除责任
- 满足开闭原则:新增处理者只需要在客户端重新建链即可,无需修改原有代码
- 每个处理者只需关注自己负责的处理逻辑:符合单一职责原则
6.2 缺点
- 不保证请求一定被处理:请求可能到了链的末端都得不到处理
- 系统性能问题:责任链过长时,请求处理可能涉及多个处理对象,影响性能
- 调试不方便:责任链过长时,调试时不容易分析处理请求的过程
7. 责任链模式的适用场景
- 多个对象可以处理同一请求,但具体由哪个对象处理在运行时确定
- 在不明确指定接收者的情况下,向多个对象中的一个提交请求
- 需要动态指定一组对象处理请求
常见应用场景:
- 审批流程
- 过滤器链
- 事件传播机制
- 异常处理机制
- 中间件设计
8. 责任链模式在框架中的应用
8.1 Servlet过滤器链
Java Web开发中的Servlet过滤器链就是责任链模式的典型应用:
public interface Filter {
void init(FilterConfig filterConfig) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
void destroy();
}
public interface FilterChain {
void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
}
8.2 Spring MVC中的拦截器链
Spring MVC中的拦截器链也是责任链模式的应用:
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception;
}
9. 责任链模式与其他设计模式的区别与联系
9.1 责任链模式与装饰器模式
- 相似点:两者都是通过对象链来实现功能
- 区别:
- 装饰器模式关注在不改变接口的前提下,为对象添加功能
- 责任链模式关注请求的处理者,以及请求在多个对象之间的传递过程
9.2 责任链模式与组合模式
- 相似点:都可以形成树形结构
- 区别:
- 组合模式关注部分-整体层次结构
- 责任链模式关注请求的处理流程
9.3 责任链模式与命令模式
- 相似点:都可以解耦请求发送者与接收者
- 区别:
- 命令模式封装请求为对象,支持排队、日志等操作
- 责任链模式关注处理请求的对象链,以及请求在链上的传递方式
10. 实战案例:ATM取款流程
// 钞票类
class Money {
private int amount;
public Money(int amount) {
this.amount = amount;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
// 抽象提款处理者
abstract class DispenseChain {
protected DispenseChain nextChain;
public void setNextChain(DispenseChain nextChain) {
this.nextChain = nextChain;
}
public abstract void dispense(Money money);
}
// 具体处理者:2000元
class Dispense2000 extends DispenseChain {
@Override
public void dispense(Money money) {
int amount = money.getAmount();
if (amount >= 2000) {
int count = amount / 2000;
int remainder = amount % 2000;
System.out.println("发放 " + count + " 张2000元");
if (remainder != 0 && nextChain != null) {
money.setAmount(remainder);
nextChain.dispense(money);
}
} else if (nextChain != null) {
nextChain.dispense(money);
}
}
}
// 具体处理者:500元
class Dispense500 extends DispenseChain {
@Override
public void dispense(Money money) {
int amount = money.getAmount();
if (amount >= 500) {
int count = amount / 500;
int remainder = amount % 500;
System.out.println("发放 " + count + " 张500元");
if (remainder != 0 && nextChain != null) {
money.setAmount(remainder);
nextChain.dispense(money);
}
} else if (nextChain != null) {
nextChain.dispense(money);
}
}
}
// 具体处理者:100元
class Dispense100 extends DispenseChain {
@Override
public void dispense(Money money) {
int amount = money.getAmount();
if (amount >= 100) {
int count = amount / 100;
int remainder = amount % 100;
System.out.println("发放 " + count + " 张100元");
if (remainder != 0 && nextChain != null) {
money.setAmount(remainder);
nextChain.dispense(money);
}
} else if (nextChain != null) {
nextChain.dispense(money);
}
}
}
// 具体处理者:50元
class Dispense50 extends DispenseChain {
@Override
public void dispense(Money money) {
int amount = money.getAmount();
if (amount >= 50) {
int count = amount / 50;
int remainder = amount % 50;
System.out.println("发放 " + count + " 张50元");
if (remainder != 0 && nextChain != null) {
money.setAmount(remainder);
nextChain.dispense(money);
}
} else if (nextChain != null) {
nextChain.dispense(money);
}
}
}
// 客户端:ATM
public class ATMDispenseChain {
public static void main(String[] args) {
// 构建责任链
DispenseChain dispense2000 = new Dispense2000();
DispenseChain dispense500 = new Dispense500();
DispenseChain dispense100 = new Dispense100();
DispenseChain dispense50 = new Dispense50();
dispense2000.setNextChain(dispense500);
dispense500.setNextChain(dispense100);
dispense100.setNextChain(dispense50);
// 取款测试
Money money1 = new Money(4750);
System.out.println("请求提款金额:" + money1.getAmount());
dispense2000.dispense(money1);
System.out.println();
Money money2 = new Money(1270);
System.out.println("请求提款金额:" + money2.getAmount());
dispense2000.dispense(money2);
System.out.println("无法处理的金额:" + money2.getAmount() % 50);
}
}
11. 总结
责任链模式是一种灵活且强大的设计模式,尤其适用于处理流程化的请求处理场景。它通过将请求的发送者和接收者解耦,提高了系统的灵活性和可扩展性。
责任链模式的关键点:
- 抽象出请求处理者的统一接口或抽象类
- 每个处理者只关注自己能处理的请求类型
- 构建一条处理链,让请求在链上传递
- 客户端只需要访问链的头部节点
使用责任链模式时需要注意的问题:
- 合理设计链的长度,避免链过长导致性能问题
- 注意处理请求可能不被处理的情况
- 根据需求决定是"一个处理完就结束"还是"所有处理者都要处理"
通过本文的介绍和示例,希望读者对责任链模式有了全面的了解,并能在实际开发中合理应用这一模式。