责任链模式(Chain of Responsibility Pattern)

1. 责任链模式概述

1.1 定义

责任链模式是一种行为型设计模式,它将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

1.2 基本思想

责任链模式的核心思想是:

  • 将能够处理同一类请求的对象连成一条链
  • 请求沿着链传递,直到有一个对象处理它
  • 客户端不需要知道是哪个对象处理了请求

2. 责任链模式的结构

责任链模式包含以下角色:

  • 抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接
  • 具体处理者(ConcreteHandler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以则处理,否则将请求转给后继者
  • 客户端(Client):创建责任链,并向链上的具体处理者对象提交请求

3. 责任链模式的UML类图

┌───────────────┐          ┌─────────────────┐
│     Client    │─────────>│ <<interface>>   │
└───────────────┘          │     Handler     │
                           ├─────────────────┤
                           │ +successor      │
                           │ +handleRequest()│
                           └────────┬────────┘
                                    │
                                    │
             ┌─────────────────────┼─────────────────────┐
             │                     │                     │
┌────────────▼───────────┐ ┌──────▼───────────────┐ ┌───▼────────────────────┐
│   ConcreteHandler1     │ │    ConcreteHandler2  │ │     ConcreteHandler3   │
├────────────────────────┤ ├──────────────────────┤ ├──────────────────────────┤
│ +handleRequest()       │ │ +handleRequest()     │ │ +handleRequest()         │
└────────────────────────┘ └──────────────────────┘ └──────────────────────────┘

4. 责任链模式的工作原理

  1. 客户端创建各个处理者对象,并组装成一条链
  2. 客户端将请求发送给链中的第一个处理者
  3. 处理者对象判断是否能处理该请求:
    • 如果能处理,则处理该请求
    • 如果不能处理,则将请求转发给下一个处理者
  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 优点

  1. 降低耦合度:将请求的发送者和接收者解耦,发送者无需知道请求被谁处理
  2. 增强了给对象指派职责的灵活性:通过改变链内的成员或调整它们的次序,允许动态地新增或删除责任
  3. 满足开闭原则:新增处理者只需要在客户端重新建链即可,无需修改原有代码
  4. 每个处理者只需关注自己负责的处理逻辑:符合单一职责原则

6.2 缺点

  1. 不保证请求一定被处理:请求可能到了链的末端都得不到处理
  2. 系统性能问题:责任链过长时,请求处理可能涉及多个处理对象,影响性能
  3. 调试不方便:责任链过长时,调试时不容易分析处理请求的过程

7. 责任链模式的适用场景

  1. 多个对象可以处理同一请求,但具体由哪个对象处理在运行时确定
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交请求
  3. 需要动态指定一组对象处理请求

常见应用场景:

  • 审批流程
  • 过滤器链
  • 事件传播机制
  • 异常处理机制
  • 中间件设计

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. 总结

责任链模式是一种灵活且强大的设计模式,尤其适用于处理流程化的请求处理场景。它通过将请求的发送者和接收者解耦,提高了系统的灵活性和可扩展性。

责任链模式的关键点:

  1. 抽象出请求处理者的统一接口或抽象类
  2. 每个处理者只关注自己能处理的请求类型
  3. 构建一条处理链,让请求在链上传递
  4. 客户端只需要访问链的头部节点

使用责任链模式时需要注意的问题:

  1. 合理设计链的长度,避免链过长导致性能问题
  2. 注意处理请求可能不被处理的情况
  3. 根据需求决定是"一个处理完就结束"还是"所有处理者都要处理"

通过本文的介绍和示例,希望读者对责任链模式有了全面的了解,并能在实际开发中合理应用这一模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈凯哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值