Java设计模式:责任链模式

news2025/6/10 11:34:10

一、什么是责任链模式?

责任链模式(Chain of Responsibility Pattern) 是一种 行为型设计模式,它通过将请求沿着一条处理链传递,直到某个对象处理它为止。这种模式的核心思想是 解耦请求的发送者和接收者,使多个对象都有机会处理请求,避免请求发送者与具体处理者之间的紧耦合。

核心角色

  • 抽象处理者(Handler)

    • 定义处理请求的接口,包含一个指向下一个处理者的引用(nextHandler)。
    • 提供设置后续处理者的方法(setNextHandler),用于构建责任链。
  • 具体处理者(ConcreteHandler)

    • 实现抽象处理者的处理方法,判断自己是否有权限处理请求:
      • 若有权,处理请求并结束流程;
      • 若无权,将请求传递给后续处理者(nextHandler.handleRequest)。
  • 客户端(Client)

    • 创建责任链,并向链的起点发送请求,无需知道具体是哪个处理者处理了请求。

二、责任链模式的核心思想

责任链模式的核心是 “链式传递”“责任分配” 的分离。

  • 链式传递:请求从链的起点开始,依次传递给每个处理者,直到某个处理者处理它。
  • 责任分配:每个处理者只负责自己职责范围内的请求,超出范围的请求则传递给下一个处理者。

生活中的例子

想象你在公司提交一个报销申请,流程如下:

  1. 直接主管审批(1000元以下);
  2. 部门经理审批(1000-5000元);
  3. 财务总监审批(5000元以上)。
    这就是一个典型的责任链模式,每个审批人只处理自己权限范围内的请求,超出权限则传递给下一个审批人。

三、Java实现责任链模式

1. 基础示例:请假审批系统

(1)定义抽象处理者

// 抽象处理者类:定义了处理请求的接口和设置下一个处理者的方法
public abstract class LeaveHandler {
    // 持有下一个处理者的引用,形成链式结构
    protected LeaveHandler nextHandler;

    // 设置下一个处理者
    public void setNextHandler(LeaveHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 抽象方法:具体处理者需要实现该方法来处理请求
    public abstract void handleRequest(LeaveRequest request);
}

(2)定义具体处理者

// 具体处理者:小组长,处理1-3天的请假请求
public class TeamLeader extends LeaveHandler {
    @Override
    public void handleRequest(LeaveRequest request) {
        // 判断是否在自己的处理范围内
        if (request.getDays() <= 3) {
            System.out.println("小组长批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
        } else if (nextHandler != null) {
            // 超出处理范围且存在下一个处理者,将请求传递
            nextHandler.handleRequest(request);
        } else {
            // 没有合适的处理者
            System.out.println("无人能处理该请求");
        }
    }
}

// 具体处理者:经理,处理3-7天的请假请求
public class Manager extends LeaveHandler {
    @Override
    public void handleRequest(LeaveRequest request) {
        // 判断是否在自己的处理范围内
        if (request.getDays() <= 7) {
            System.out.println("经理批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
        } else if (nextHandler != null) {
            // 超出处理范围且存在下一个处理者,将请求传递
            nextHandler.handleRequest(request);
        } else {
            // 没有合适的处理者
            System.out.println("无人能处理该请求");
        }
    }
}

// 具体处理者:总监,处理7天以上的请假请求
public class Director extends LeaveHandler {
    @Override
    public void handleRequest(LeaveRequest request) {
        // 判断是否在自己的处理范围内
        if (request.getDays() > 7) {
            System.out.println("总监批准了 " + request.getName() + " 的 " + request.getDays() + " 天请假");
        } else if (nextHandler != null) {
            // 超出处理范围且存在下一个处理者,将请求传递
            nextHandler.handleRequest(request);
        } else {
            // 没有合适的处理者
            System.out.println("无人能处理该请求");
        }
    }
}

(3)定义请求类

// 请假请求类:封装了请假的相关信息
public class LeaveRequest {
    private String name;  // 请假人姓名
    private int days;     // 请假天数
    private String reason; // 请假原因

    public LeaveRequest(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; }
}

(4)客户端调用

// 客户端类:构建责任链并提交请求
public class Client {
    public static void main(String[] args) {
        // 1. 构建责任链:按照 小组长 -> 经理 -> 总监 的顺序设置
        LeaveHandler teamLeader = new TeamLeader();
        LeaveHandler manager = new Manager();
        LeaveHandler director = new Director();

        // 设置责任链顺序
        teamLeader.setNextHandler(manager);
        manager.setNextHandler(director);

        // 2. 创建请假请求
        LeaveRequest request1 = new LeaveRequest("张三", 2, "生病");  // 2天请假,应由小组长处理
        LeaveRequest request2 = new LeaveRequest("李四", 10, "家庭事务"); // 10天请假,应由总监处理

        // 3. 提交请求到责任链的起点(小组长)
        // 当调用 teamLeader.handleRequest(request1) 时:
        // - 小组长判断2天 <=3天,直接处理该请求
        teamLeader.handleRequest(request1);
        
        // 当调用 teamLeader.handleRequest(request2) 时:
        // - 小组长判断10天 >3天,将请求传递给经理
        // - 经理判断10天 >7天,将请求传递给总监
        // - 总监判断10天 >7天,处理该请求
        teamLeader.handleRequest(request2);
    }
}

⑸、流程图和内存图

2.责任链模式的经典实现

下面通过一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限:

(1)定义抽象处理者

// Approver.java
public abstract class Approver {
    protected Approver successor; // 下一个处理者

    // 设置下一个处理者
    public void setSuccessor(Approver successor) {
        this.successor = successor;
    }

    // 处理请求的抽象方法
    public abstract void processRequest(PurchaseRequest request);
}

(2)定义具体处理者

// Director.java
public class Director extends Approver {
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 10000) {
            System.out.println("主任审批了金额为 " + request.getAmount() + " 的采购申请");
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

// Manager.java
public class Manager extends Approver {
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 50000) {
            System.out.println("经理审批了金额为 " + request.getAmount() + " 的采购申请");
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

// VicePresident.java
public class VicePresident extends Approver {
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 100000) {
            System.out.println("副总裁审批了金额为 " + request.getAmount() + " 的采购申请");
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

// President.java
public class President extends Approver {
    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 500000) {
            System.out.println("总裁审批了金额为 " + request.getAmount() + " 的采购申请");
        } else {
            System.out.println("金额过大,需要董事会讨论");
        }
    }
}

(3)定义请求类

// PurchaseRequest.java
public class PurchaseRequest {
    private double amount; // 金额
    private String purpose; // 用途

    public PurchaseRequest(double amount, String purpose) {
        this.amount = amount;
        this.purpose = purpose;
    }

    public double getAmount() {
        return amount;
    }

    public String getPurpose() {
        return purpose;
    }
}

(4)客户端调用

// Client.java
public class Client {
    public static void main(String[] args) {
        // 创建处理者
        Approver director = new Director();
        Approver manager = new Manager();
        Approver vicePresident = new VicePresident();
        Approver president = new President();

        // 设置责任链
        director.setSuccessor(manager);
        manager.setSuccessor(vicePresident);
        vicePresident.setSuccessor(president);

        // 创建采购申请
        PurchaseRequest request1 = new PurchaseRequest(5000, "购买办公用品");
        PurchaseRequest request2 = new PurchaseRequest(30000, "购买电脑设备");
        PurchaseRequest request3 = new PurchaseRequest(80000, "购买服务器");
        PurchaseRequest request4 = new PurchaseRequest(300000, "购买办公大楼");

        // 处理请求
        director.processRequest(request1);
        director.processRequest(request2);
        director.processRequest(request3);
        director.processRequest(request4);
    }
}

在这个示例中,我们创建了一个审批链,从主任到经理、副总裁,最后到总裁。每个审批者根据自己的权限处理请求,如果无法处理则将请求传递给下一个审批者。客户端只需要将请求发送给链头的处理者,无需关心具体是哪个处理者最终处理了请求。


能不能连写?return this;返回的是谁


四、责任链模式在 Java 中的实际应用

责任链模式在 Java 中有许多实际应用场景,例如:

  1. Servlet 过滤器链:在 Java Web 应用中,Servlet 过滤器可以形成一个链,每个过滤器负责特定的任务,如编码转换、权限验证等。
  2. 日志记录系统:不同级别的日志可以由不同的处理器处理,如控制台日志、文件日志、数据库日志等。
  3. 异常处理链:多个异常处理器可以按顺序尝试处理异常。

下面是一个使用 Java 8 函数式编程简化责任链模式的示例:

import java.util.function.Consumer;

public class FunctionalChainExample {
    public static void main(String[] args) {
        // 定义处理者
        Consumer<String> logger = message -> System.out.println("日志记录: " + message);
        Consumer<String> authChecker = message -> {
            if (message.contains("admin")) {
                System.out.println("权限验证通过");
            } else {
                System.out.println("权限验证失败");
            }
        };
        Consumer<String> processor = message -> System.out.println("处理请求: " + message);
        
        // 构建责任链
        Consumer<String> chain = logger
                .andThen(authChecker)
                .andThen(processor);
        
        // 处理请求
        chain.accept("admin:create_user");
        chain.accept("user:view_profile");
    }
}

这个示例使用 Java 8 的函数式接口和方法引用简化了责任链的实现,使代码更加简洁和灵活。

责任链模式的优缺点

优点:

  • 降低了请求发送者和接收者之间的耦合度。
  • 可以动态添加或修改处理者,提高了系统的灵活性。
  • 简化了对象间的连接,每个对象只需保持一个后续者引用。

缺点:

  • 请求可能无法被处理,因为链中没有合适的处理者。
  • 如果责任链过长,可能会影响系统性能。
  • 调试时可能会比较困难,因为请求的处理过程是隐式的。

总结

责任链模式是一种非常实用的设计模式,它将请求的发送者和接收者解耦,使多个处理者都有机会处理请求。通过合理地使用责任链模式,可以提高系统的灵活性和可维护性。在实际开发中,我们可以根据具体需求选择传统的实现方式或使用函数式编程进行简化。无论是 Servlet 过滤器链还是日志处理系统,责任链模式都能发挥其独特的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2406567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初探用uniapp写微信小程序遇到的问题及解决(vue3+ts)

零、关于开发思路 (一)拿到工作任务,先理清楚需求 1.逻辑部分 不放过原型里说的每一句话,有疑惑的部分该问产品/测试/之前的开发就问 2.页面部分(含国际化) 整体看过需要开发页面的原型后,分类一下哪些组件/样式可以复用,直接提取出来使用 (时间充分的前提下,不…

云原生时代的系统设计:架构转型的战略支点

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、云原生的崛起&#xff1a;技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深&#xff0c;传统的 I…

python可视化:俄乌战争时间线关键节点与深层原因

俄乌战争时间线可视化分析&#xff1a;关键节点与深层原因 俄乌战争是21世纪欧洲最具影响力的地缘政治冲突之一&#xff0c;自2022年2月爆发以来已持续超过3年。 本文将通过Python可视化工具&#xff0c;系统分析这场战争的时间线、关键节点及其背后的深层原因&#xff0c;全面…

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql

安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了&#xff0c;系统很多命…

【QT控件】显示类控件

目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…

npm安装electron下载太慢,导致报错

npm安装electron下载太慢&#xff0c;导致报错 背景 想学习electron框架做个桌面应用&#xff0c;卡在了安装依赖&#xff08;无语了&#xff09;。。。一开始以为node版本或者npm版本太低问题&#xff0c;调整版本后还是报错。偶尔执行install命令后&#xff0c;可以开始下载…

职坐标物联网全栈开发全流程解析

物联网全栈开发涵盖从物理设备到上层应用的完整技术链路&#xff0c;其核心流程可归纳为四大模块&#xff1a;感知层数据采集、网络层协议交互、平台层资源管理及应用层功能实现。每个模块的技术选型与实现方式直接影响系统性能与扩展性&#xff0c;例如传感器选型需平衡精度与…

【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项

一、条形码识别改名使用教程 打开软件并选择处理模式&#xff1a;打开软件后&#xff0c;根据要处理的文件类型&#xff0c;选择 “图片识别模式” 或 “PDF 识别模式”。如果是处理包含条形码的 PDF 文件&#xff0c;就选择 “PDF 识别模式”&#xff1b;若是处理图片文件&…

英国云服务器上安装宝塔面板(BT Panel)

在英国云服务器上安装宝塔面板&#xff08;BT Panel&#xff09; 是完全可行的&#xff0c;尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎&#xff0c;虽然官方主要面向中国大陆…

数据挖掘是什么?数据挖掘技术有哪些?

目录 一、数据挖掘是什么 二、常见的数据挖掘技术 1. 关联规则挖掘 2. 分类算法 3. 聚类分析 4. 回归分析 三、数据挖掘的应用领域 1. 商业领域 2. 医疗领域 3. 金融领域 4. 其他领域 四、数据挖掘面临的挑战和未来趋势 1. 面临的挑战 2. 未来趋势 五、总结 数据…

简约商务通用宣传年终总结12套PPT模版分享

IOS风格企业宣传PPT模版&#xff0c;年终工作总结PPT模版&#xff0c;简约精致扁平化商务通用动画PPT模版&#xff0c;素雅商务PPT模版 简约商务通用宣传年终总结12套PPT模版分享:商务通用年终总结类PPT模版https://pan.quark.cn/s/ece1e252d7df

【Qt】控件 QWidget

控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态&#xff1a;enabled几何&#xff1a;geometrywindows frame 窗口框架的影响 窗口标题&#xff1a;windowTitle窗口图标&#xff1a;windowIconqrc 机制 窗口不透明度&#xff1a;windowOpacity光标&#xff1a;cursor…

Linux入门课的思维导图

耗时两周&#xff0c;终于把慕课网上的Linux的基础入门课实操、总结完了&#xff01; 第一次以Blog的形式做学习记录&#xff0c;过程很有意思&#xff0c;但也很耗时。 课程时长5h&#xff0c;涉及到很多专有名词&#xff0c;要去逐个查找&#xff0c;以前接触过的概念因为时…

aurora与pcie的数据高速传输

设备&#xff1a;zynq7100&#xff1b; 开发环境&#xff1a;window&#xff1b; vivado版本&#xff1a;2021.1&#xff1b; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程&#xff0c;pc通过pcie传输给fpga&#xff0c;fpga再通过aur…

Springboot 高校报修与互助平台小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;高校报修与互助平台小程序被用户普遍使用&#xff0c;为…

Linux 内存管理调试分析:ftrace、perf、crash 的系统化使用

Linux 内存管理调试分析&#xff1a;ftrace、perf、crash 的系统化使用 Linux 内核内存管理是构成整个内核性能和系统稳定性的基础&#xff0c;但这一子系统结构复杂&#xff0c;常常有设置失败、性能展示不良、OOM 杀进程等问题。要分析这些问题&#xff0c;需要一套工具化、…

MLP实战二:MLP 实现图像数字多分类

任务 实战&#xff08;二&#xff09;&#xff1a;MLP 实现图像多分类 基于 mnist 数据集&#xff0c;建立 mlp 模型&#xff0c;实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入&#xff0c;可视化图形数字&#xff1b; 2、完成数据预处理&#xff1a;图像数据维度转换与…

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器

从本章节开始&#xff0c;进入到函数有多个参数的情况&#xff0c;前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参&#xff0c;ECX是整型的第一个参数的寄存器&#xff0c;那么多个参数的情况下函数如何传参&#xff0c;下面展开介绍参数为整型时候的几种情…

PLC入门【4】基本指令2(SET RST)

04 基本指令2 PLC编程第四课基本指令(2) 1、运用上接课所学的基本指令完成个简单的实例编程。 2、学习SET--置位指令 3、RST--复位指令 打开软件(FX-TRN-BEG-C)&#xff0c;从 文件 - 主画面&#xff0c;“B: 让我们学习基本的”- “B-3.控制优先程序”。 点击“梯形图编辑”…