设计模式之责任链模式:原理、实现与应用
引言
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者与接收者之间的耦合。责任链模式通过将多个处理对象连接成一条链,使得请求沿着链传递,直到有对象处理它为止。本文将深入探讨责任链模式的原理、实现方式以及实际应用场景,帮助你更好地理解和使用这一设计模式。
1. 责任链模式的核心概念
1.1 什么是责任链模式?
责任链模式是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者与接收者之间的耦合。责任链模式通过将多个处理对象连接成一条链,使得请求沿着链传递,直到有对象处理它为止。
1.2 责任链模式的应用场景
-
多级审批:如请假审批、报销审批等。
-
事件处理:如GUI事件处理、异常处理等。
-
过滤器链:如Web请求过滤器、日志过滤器等。
2. 责任链模式的实现方式
2.1 基本结构
责任链模式通常包含以下几个角色:
-
处理者接口(Handler):定义处理请求的接口,并持有下一个处理者的引用。
-
具体处理者(Concrete Handler):实现处理者接口,处理请求或将请求传递给下一个处理者。
-
客户端(Client):创建责任链,并向链中的第一个处理者发送请求。
2.2 代码示例
// 处理者接口
public interface Handler {void setNext(Handler next);void handleRequest(Request request);
}// 具体处理者A
public class ConcreteHandlerA implements Handler {private Handler next;@Overridepublic void setNext(Handler next) {this.next = next;}@Overridepublic void handleRequest(Request request) {if (request.getType().equals("TypeA")) {System.out.println("ConcreteHandlerA handled the request");} else if (next != null) {next.handleRequest(request);}}
}// 具体处理者B
public class ConcreteHandlerB implements Handler {private Handler next;@Overridepublic void setNext(Handler next) {this.next = next;}@Overridepublic void handleRequest(Request request) {if (request.getType().equals("TypeB")) {System.out.println("ConcreteHandlerB handled the request");} else if (next != null) {next.handleRequest(request);}}
}// 请求类
public class Request {private String type;public Request(String type) {this.type = type;}public String getType() {return type;}
}// 客户端代码
public class Client {public static void main(String[] args) {Handler handlerA = new ConcreteHandlerA();Handler handlerB = new ConcreteHandlerB();handlerA.setNext(handlerB);Request request1 = new Request("TypeA");handlerA.handleRequest(request1);Request request2 = new Request("TypeB");handlerA.handleRequest(request2);Request request3 = new Request("TypeC");handlerA.handleRequest(request3);}
}
3. 责任链模式的最佳实践
3.1 动态构建责任链
-
灵活性:通过动态构建责任链,可以根据需要调整处理者的顺序和数量。
-
可扩展性:通过添加新的处理者,可以轻松扩展责任链的功能。
3.2 避免循环引用
-
循环引用:在构建责任链时,避免处理者之间形成循环引用,导致请求无限循环。
3.3 遵循单一职责原则
-
单一职责:每个处理者只负责处理特定类型的请求,保持职责单一。
-
高内聚低耦合:责任链模式使得系统更加高内聚低耦合。
4. 责任链模式的实际应用
4.1 多级审批
在多级审批中,责任链模式用于处理不同级别的审批请求。
// 处理者接口
public interface Approver {void setNext(Approver next);void approve(int amount);
}// 具体处理者
public class Manager implements Approver {private Approver next;@Overridepublic void setNext(Approver next) {this.next = next;}@Overridepublic void approve(int amount) {if (amount <= 1000) {System.out.println("Manager approved the request");} else if (next != null) {next.approve(amount);}}
}public class Director implements Approver {private Approver next;@Overridepublic void setNext(Approver next) {this.next = next;}@Overridepublic void approve(int amount) {if (amount <= 5000) {System.out.println("Director approved the request");} else if (next != null) {next.approve(amount);}}
}public class CEO implements Approver {@Overridepublic void setNext(Approver next) {// CEO is the final approver}@Overridepublic void approve(int amount) {System.out.println("CEO approved the request");}
}// 客户端代码
public class Client {public static void main(String[] args) {Approver manager = new Manager();Approver director = new Director();Approver ceo = new CEO();manager.setNext(director);director.setNext(ceo);manager.approve(500);manager.approve(2000);manager.approve(10000);}
}
4.2 事件处理
在事件处理中,责任链模式用于处理不同类型的事件。
// 处理者接口
public interface EventHandler {void setNext(EventHandler next);void handle(Event event);
}// 具体处理者
public class MouseEventHandler implements EventHandler {private EventHandler next;@Overridepublic void setNext(EventHandler next) {this.next = next;}@Overridepublic void handle(Event event) {if (event.getType().equals("MouseEvent")) {System.out.println("MouseEventHandler handled the event");} else if (next != null) {next.handle(event);}}
}public class KeyboardEventHandler implements EventHandler {private EventHandler next;@Overridepublic void setNext(EventHandler next) {this.next = next;}@Overridepublic void handle(Event event) {if (event.getType().equals("KeyboardEvent")) {System.out.println("KeyboardEventHandler handled the event");} else if (next != null) {next.handle(event);}}
}// 事件类
public class Event {private String type;public Event(String type) {this.type = type;}public String getType() {return type;}
}// 客户端代码
public class Client {public static void main(String[] args) {EventHandler mouseHandler = new MouseEventHandler();EventHandler keyboardHandler = new KeyboardEventHandler();mouseHandler.setNext(keyboardHandler);Event mouseEvent = new Event("MouseEvent");mouseHandler.handle(mouseEvent);Event keyboardEvent = new Event("KeyboardEvent");mouseHandler.handle(keyboardEvent);Event unknownEvent = new Event("UnknownEvent");mouseHandler.handle(unknownEvent);}
}
4.3 过滤器链
在过滤器链中,责任链模式用于处理Web请求或日志记录。
// 处理者接口
public interface Filter {void setNext(Filter next);void doFilter(Request request);
}// 具体处理者
public class AuthenticationFilter implements Filter {private Filter next;@Overridepublic void setNext(Filter next) {this.next = next;}@Overridepublic void doFilter(Request request) {if (request.getType().equals("Authentication")) {System.out.println("AuthenticationFilter handled the request");} else if (next != null) {next.doFilter(request);}}
}public class LoggingFilter implements Filter {private Filter next;@Overridepublic void setNext(Filter next) {this.next = next;}@Overridepublic void doFilter(Request request) {if (request.getType().equals("Logging")) {System.out.println("LoggingFilter handled the request");} else if (next != null) {next.doFilter(request);}}
}// 请求类
public class Request {private String type;public Request(String type) {this.type = type;}public String getType() {return type;}
}// 客户端代码
public class Client {public static void main(String[] args) {Filter authenticationFilter = new AuthenticationFilter();Filter loggingFilter = new LoggingFilter();authenticationFilter.setNext(loggingFilter);Request authRequest = new Request("Authentication");authenticationFilter.doFilter(authRequest);Request logRequest = new Request("Logging");authenticationFilter.doFilter(logRequest);Request unknownRequest = new Request("Unknown");authenticationFilter.doFilter(unknownRequest);}
}
5. 责任链模式的优缺点
5.1 优点
-
解耦:责任链模式将请求的发送者与接收者解耦,使得请求的发送者无需知道具体的处理者。
-
灵活性:通过动态构建责任链,可以根据需要调整处理者的顺序和数量。
-
可扩展性:通过添加新的处理者,可以轻松扩展责任链的功能。
5.2 缺点
-
性能问题:如果责任链过长,可能会导致性能问题。
-
请求未被处理:如果请求未被任何处理者处理,可能会导致请求丢失。
结语
责任链模式是设计模式中用于处理请求的经典模式之一,适用于需要将请求的发送者与接收者解耦的场景。通过掌握责任链模式的原理、实现方式以及最佳实践,你可以在实际开发中更好地应用这一模式。希望本文能为你的设计模式学习之旅提供一些实用的指导!
如果你有具体的需求或想要深入探讨某个主题,请告诉我,我可以进一步调整内容!
相关文章:
设计模式之责任链模式:原理、实现与应用
引言 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它允许多个对象有机会处理请求,从而避免请求的发送者与接收者之间的耦合。责任链模式通过将多个处理对象连接成一条链,使得请求沿着链传递&am…...
20250318在ubuntu20.04中安装向日葵
rootrootrootroot-X99-Turbo:~$ sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb rootrootrootroot-X99-Turbo:~$ sudo apt-get install -f rootrootrootroot-X99-Turbo:~$ sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb 20250318在ubuntu20.04中安装向日葵 2025/3…...
Kotlin的 noinline和crossinline关键字
noinline 顾名思义,noinline的意思就是不内联,这个关键字只能作用于内联高阶函数的某个函数类型的参数上,表明当前的函数参数不参与高阶函数的内联: inline fun fun1(doSomething1: () -> Unit, noinline doSomething2: () -&…...
区块链交易签名相关知识总结
基础概念 签名流程 安全相关问题 实际场景 代码示例 进阶问题 一、基础概念 1. 为什么区块链交易需要签名? 答案: 身份认证:证明交易由私钥持有者发起。 数据完整性:确保交易内容未被篡改。 抗抵赖性:签名者无…...
Spring Boot集成Redis并设置密码后报错: NOAUTH Authentication required
报错信息: io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required.Redis密码配置确认无误,但是只要使用Redis存储就报这个异常。很可能是因为配置的spring.redis.password没有被读取到。 基本依赖: implementat…...
如何记录Matlab程序运行过程中所占用的最大内存(续)
在上一篇博客中,我们讨论了如何记录Matlab程序运行过程中所占用的最大内存。 博客原文:如何记录Matlab程序运行过程中所占用的最大内存-CSDN博客 但经过测试发现,这与实际有非常大的差异。运行如下例子: clear;clc; profile on…...
分布式节点池:群联云防护抗DDoS的核心武器
一、节点池的核心作用与架构设计 1. 全球分布式节点布局 物理层防御: 根据产品文档,群联在全球部署“海量分布式节点”,每个节点具备独立清洗能力,攻击流量被分散至不同区域节点处理。优势:避免传统单节点防护的瓶颈&…...
Java线程池深度解析:从使用到调优
适合人群:Java中级开发者 | 并发编程入门者 | 系统调优实践者 目录 一、引言:为什么线程池是Java并发的核心? 二、线程池核心知识点详解 1. 线程池核心参数与原理 2. 线程池的创建与使用 (1) 基础用法示例 (2) 内置线程池的隐患 3. 线…...
自动驾驶背后的数学:多模态传感器融合的简单建模
上一篇博客自动驾驶背后的数学:特征提取中的线性变换与非线性激活 以单个传感器为例,讲解了特征提取中的线性变换与非线性激活。 这一篇将以多模态传感器融合为例,讲解稍复杂的线性变换和非线性激活应用场景。 (一)权重矩阵的张量积分解 y = W x + b = [ w 11 ⋯ w 1 n ⋮…...
12 File文件对象:创建、获取基本信息、遍历文件夹、查找文件;字符集的编解码 (黑马Java视频笔记)
文章目录 File >> 存储数据的方案1. 认识File2. File操作2.1 创建File对象2.2 File操作1)对文件对象的信息的操作2)文件/文件夹的创建/删除3)⭐⭐对文件夹的遍历 3. 方法递归3.1 认识递归3.2 递归算法及其执行流程1) 案例:2…...
HTML应用指南:利用GET请求获取猫眼电影日票房信息——以哪吒2为例
2025年春节档期,国产动画电影《哪吒之魔童闹海》(以下简称《哪吒2》)以颠覆性的叙事风格与工业化制作水准震撼登场,不仅刷新了中国动画电影的票房纪录,更成为全球影史现象级作品。影片凭借春节档期的爆发式开局、持续5…...
荣耀手机卸载应用商店、快应用中心等系统自带的
1.下载abd ADB Download - Get the latest version of ADB and fastboot 2.手机打开开发者选项 3.手机接电脑打开USB调试 4.下载MT管理器查看系统包名 D:\1.LFD\ADB\platform-tools-latest-windows\platform-tools>adb shell adb.exe: no devices/emulators found 这边是…...
[AI速读]用持续集成(CI)优化芯片验证环境:Jenkins与EDA工具的实战指南
在芯片验证中,回归测试(Regression Test)是确保设计稳定性的关键步骤。但随着设计复杂度增加,手动管理海量测试用例、分析日志和覆盖率数据变得异常耗时。本文将介绍如何利用持续集成(CI)工具Jenkins,结合EDA验证环境(如Cadence vManager),实现自动化测试与结果分析,…...
苍穹外卖学习笔记
整体概述 1).用户层 本项目中在构建系统管理后台的前端页面,我们会用到H5、Vue.js、ElementUI、apache echarts(展示图表)等技术。而在构建移动端应用时,我们会使用到微信小程序 2).网关层 Nginx是一个服务器,主要用来作为Http服务器&…...
Spring常用注解汇总
1. IOC容器与Bean管理 注解说明示例Component通用注解,标记类为Spring Bean Component public class MyService { ... } Controller标记Web控制器(应用在MVC的控制层) Controller public class UserController { ... } Service标记业务逻辑层…...
深度强化学习中的深度神经网络优化策略:挑战与解决方案
I. 引言 深度强化学习(Deep Reinforcement Learning,DRL)结合了强化学习(Reinforcement Learning,RL)和深度学习(Deep Learning)的优点,使得智能体能够在复杂的环境中学…...
每日一题力扣2974.最小数字游戏c++
2974. 最小数字游戏 - 力扣(LeetCode) class Solution { public:vector<int> numberGame(vector<int>& nums) {vector<int> arr(nums.size());sort(nums.begin(),nums.end());for(size_t i0;i<nums.size();i2){arr[i]nums[i1]…...
软考中级-软件设计师 准备
软考中级-软件设计师 准备 一、软考相关1.1、考试时间1.2、考试时长1.3、题型和分值: 二、软考备考2.1、相关书籍2.2、推荐课程:B站up主zst_20012.3、学习路线 一、软考相关 1.1、考试时间 一年有两次软考,一般是五月末和十一月的中旬 以下…...
EasyRTC嵌入式音视频通信SDK:WebRTC技术下的硬件与软件协同演进,开启通信新时代
在当今数字化时代,智能设备的普及和人们对实时通信需求的不断增长,推动了嵌入式音视频通信技术的快速发。EasyRTC嵌入式音视频通信SDK凭借其独特的技术特点和应用优势,在嵌入式设备和多平台实时通信领域脱颖而出。 1、轻量级设计与高性能 Ea…...
lua垃圾回收
lua垃圾回收 lua 垃圾回收 lua 垃圾回收 collectgarbage(“count”)获取当前lua脚本占用内存字节数(单位为KB)。 collectgarbage(“collect”)执行一次垃圾回收。 xxxnil 将变量置为空,会释放内存。 lua中的机制和c#中回收机制很类似 解除羁绊(置为空)。 --垃圾回…...
Lineageos 22.1(Android 15)实现负一屏
一、前言 方案是参考的这位大佬的,大家可以去付费订阅支持一波。我大概理一下Android15的修改。 大佬的方案代码 二、Android15适配调整 1.bp调整,加入aidl引入,这样make之后就可以索引代码了 filegroup {name: "launcher-src"…...
《深度学习》——YOLOv3详解
文章目录 YOLOv3简介YOLOv3核心原理YOLOv3改进YOLOv3网络结构 YOLOv3简介 YOLOv3(You Only Look Once, version 3)是一种先进的实时目标检测算法,由 Joseph Redmon 和 Ali Farhadi 开发。它在目标检测领域表现出色,具有速度快、精…...
【设计模式】三十一、状态模式
系列文章|源码 https://github.com/tyronczt/design-mode-learn 文章目录 系列文章|源码一、模式核心思想二、模式结构三、Java代码示例:订单状态管理1. 定义状态接口2. 实现具体状态类3. 上下文类(Context)4. 客户端调用5. 运行截图 四、状…...
vue 获取当前时间并自动刷新
新增需求,需要在大屏的右上角展示当前时间,并实时按秒刷新,通过通义千问搜索关键js代码后,整理出如下代码。 【效果图】 【HTML】 <div class"time-wrap">{{ formattedDateTime }}<span> {{ weekTime }}&…...
C 语 言 --- 扫 雷 游 戏(初 阶 版)
C 语 言 --- 扫 雷 游 戏 初 阶 版 代 码 全 貌 与 功 能 介 绍扫雷游戏的功能说明游 戏 效 果 展 示游 戏 代 码 详 解game.htest.cgame.c 总结 💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 C 语 言 💡个 人 主…...
WebDeveloper靶机详解
一、主机发现 arp-scan -l靶机ip为192.168.55.163 二、端口扫描、目录枚举、漏洞扫描、指纹识别 2.1端口扫描 nmap --min-rate 10000 -p- 192.168.55.163发现并无特殊端口开放 扫描一下UDP端口 nmap -sU --min-rate 10000 -p- 192.168.55.163没有扫描到UDP端口 2.2目录枚…...
Cursor IDE 入门指南
什么是 Cursor? Cursor 是一款集成了 AI 功能的现代代码编辑器,基于 VSCode 开发,专为提高开发效率而设计。它内置强大的 AI 助手功能,能够理解代码、生成代码、解决问题,帮助开发者更快、更智能地完成编程任务。 基础功能 1.…...
来源于胡椒的亚甲二氧桥CYP450-文献精读119
Piper nigrum CYP719A37 Catalyzes the Decisive Methylenedioxy Bridge Formation in Piperine Biosynthesis 胡椒 (Piper nigrum) CYP719A37 催化胡椒碱生物合成中关键的亚甲二氧桥形成 摘要 胡椒 (Piper nigrum) 是世界上最受欢迎的香料之一。其主要辛辣成分胡椒碱 (piper…...
STM32八股【1】-----启动流程和startup文件理解
启动流程 知识点 MCU 上电复位。MSP从向量表第0个地址读取一个32位(2字节)的值并保存,该值为栈顶地址。PC计数器从第1个地址读取一个两字节的值并保存,该值为程序入口,一般是Reset_Handler。想了解FLASH地址映射可以…...
Docker与K8S是什么该怎么选?
用了很久的容器化,最近突然看到一个问题问: docker和K8S究竟有什么区别,到底该怎么选?我认真思考了一会,发现一时间还真说不明白,于是就研究了一段时间发布今天的博文! Docker vs Kubernetes&a…...
