03-JAVA设计模式-责任链模式

责任链模式

什么是责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,允许你将请求沿着处理者链进行传递。每个处理者均对请求进行某些处理,并可决定是否将请求沿着链传递下去。这种模式给予请求的处理者更加灵活的组织结构。

在Java中实现责任链模式,通常需要定义一个处理者接口,该接口包含一个或多个方法用于处理请求和决定是否传递请求。

然后,创建具体的处理者类,实现这个接口。 每个处理者可以持有对下一个处理者的引用,从而形成处理者链。

  • 优点

    • 降低了耦合度: 责任链模式通过将请求的处理逻辑分散到多个处理对象中,减少了请求发送者与多个请求处理者之间的耦合。请求发送者只需要将请求发送到链的头部,而不需要知道链的具体结构或处理逻辑。
    • 增强了系统的可扩展性: 当需要增加新的处理逻辑时,只需要创建一个新的处理对象并将其添加到链中即可,无需修改现有代码。这使得系统的扩展变得更加容易和灵活。
    • 提高了系统的灵活性: 每个处理对象都可以独立地决定是否处理请求,以及是否将请求传递给下一个处理对象。这种灵活性使得系统可以根据不同的场景和需求进行动态调整。
    • 实现了请求的有序处理: 通过合理地安排处理对象在链中的顺序,可以确保请求按照特定的顺序进行处理。这对于某些需要按照特定顺序执行的操作非常有用。
  • 缺点

    • 可能导致性能问题: 由于请求需要在多个处理对象之间进行传递,因此可能会增加系统的处理时间。特别是在处理链较长或处理逻辑较复杂的情况下,性能问题可能会更加明显。
    • 调试难度较大: 当责任链较长且处理逻辑复杂时,调试可能会变得相对困难。因为请求在多个处理对象之间传递,定位问题的来源可能需要跨越多个类和方法。
    • 可能导致请求丢失: 如果没有正确设置处理对象的下一个引用,或者处理对象在处理请求时出现了异常,可能会导致请求在链中丢失,从而无法得到处理。
    • 可能增加代码的复杂性: 为了实现责任链模式,需要编写多个处理对象的代码,并确保它们之间的正确连接和传递。这可能会增加代码的复杂性,特别是在处理逻辑较为复杂的情况下。

开发中常见场景

  • java中,异常机制就是一种责任链模式
  • Servlet开发中,过滤器的链式处理
  • Struts2中,拦截器的调用也是典型的责任链模式

案例

公司里,请假条的审批流程:

  • 请假天数小于3天,主任审批
  • 请假天数大于3天,小于10天,经理审批
  • 请假天数大于10天,小于30天,总经理审批
  • 请假天数大于30天,提示拒绝

UML

  • 定义请假单,包含请假人,请假天数,请假原因属性
  • 定义一个处理者接口,并提供两个接口:
    • 自己的处理方式
    • 设置下一处理者
  • 定义主任、经理,总经理三个处理者,定义一个属性存储下一处理者引用,自己处理方式接口中,根据需求进行判断处理,否则调用下一处理者进行处理

实现代码

LeaveOrder.java

java 复制代码
// 请假单
public class LeaveOrder {
    // 请假人
    private String name;
    // 请假天数
    private int days;
    // 原因
    private String reason;

    public LeaveOrder(String name, int days, String reason) {
        this.name = name;
        this.days = days;
        this.reason = reason;
    }

    public String getName() {
        return name;
    }

    public int getDays() {
        return days;
    }

    public String getReason() {
        return reason;
    }
}

LeaveHandle.java

java 复制代码
// 定义处理者接口
public interface LeaveHandle {
    // 定义本人处理方式接口
    void handleRequest(LeaveOrder leaveOrder);
    // 定义下一处理者的引用
    void setNextHandle(LeaveHandle leaveHandle);
}

DirectorLeaveHandle.java

java 复制代码
// 主任
public class DirectorLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 3 && leaveOrder.getDays() > 0){
            System.out.printf("主任审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            // 通过持有引用 调用下已处理者进行处理
            nextHandler.handleRequest(leaveOrder);
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

ManagerLeaveHandle.java

java 复制代码
// 经理
public class ManagerLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 10 && leaveOrder.getDays() > 3){
            System.out.printf("经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            // 通过持有引用 调用下已处理者进行处理
            nextHandler.handleRequest(leaveOrder);
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

GeneralManagerLeaveHandle.java

java 复制代码
// 总经理
public class GeneralManagerLeaveHandle implements LeaveHandle{

    // 定义一个属性 用于持有下一处理者
    private LeaveHandle nextHandler;

    @Override
    public void handleRequest(LeaveOrder leaveOrder) {
        if(leaveOrder != null && leaveOrder.getDays() <= 30 && leaveOrder.getDays() > 10){
            System.out.printf("总经理审批-允许请假-请假人:%s-请假天数:%s-理由:%s%n",leaveOrder.getName(),leaveOrder.getDays(),leaveOrder.getReason());
        }
        else {
            System.out.println("超过30天拒绝请假");
        }
    }

    @Override
    public void setNextHandle(LeaveHandle leaveHandle) {
        this.nextHandler = leaveHandle;
    }
}

TestClient.java

java 复制代码
public class TestClient {
    public static void main(String[] args) {
        // 创建请假单
        LeaveOrder order = new LeaveOrder("张三",15,"回家");
         创建处理人
        // 主任
        DirectorLeaveHandle directorLeaveHandle = new DirectorLeaveHandle();
        // 经理
        ManagerLeaveHandle managerLeaveHandle = new ManagerLeaveHandle();
        // 总经理
        GeneralManagerLeaveHandle generalManagerLeaveHandle = new GeneralManagerLeaveHandle();

        // 设置责任链
        directorLeaveHandle.setNextHandle(managerLeaveHandle);
        directorLeaveHandle.setNextHandle(generalManagerLeaveHandle);

        // 提交请假申请
        directorLeaveHandle.handleRequest(order);
    }
}

执行结果:

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

相关推荐
带刺的坐椅20 分钟前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看2 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t2 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再4 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven