return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限:
// 抽象处理者:审批者
abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者public void setSuccessor(Approver successor) {this.successor = successor;}// 处理请求的抽象方法public abstract void processRequest(PurchaseRequest request);
}// 具体处理者:主任
class Director extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 10000) {System.out.println("主任审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:经理
class Manager extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 50000) {System.out.println("经理审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:副总裁
class VicePresident extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 100000) {System.out.println("副总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:总裁
class President extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 500000) {System.out.println("总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else {System.out.println("金额过大,需要董事会讨论");}}
}// 请求类
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;}
}// 客户端类
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);}
}
一、能不能连写?
// 抽象处理者:审批者
abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者并返回当前实例public Approver setSuccessor(Approver successor) {this.successor = successor;return this;}// 处理请求的抽象方法public abstract void processRequest(PurchaseRequest request);
}// 具体处理者:主任
class Director extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 10000) {System.out.println("主任审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:经理
class Manager extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 50000) {System.out.println("经理审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:副总裁
class VicePresident extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 100000) {System.out.println("副总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else if (successor != null) {successor.processRequest(request);}}
}// 具体处理者:总裁
class President extends Approver {@Overridepublic void processRequest(PurchaseRequest request) {if (request.getAmount() < 500000) {System.out.println("总裁审批了金额为 " + request.getAmount() + " 的采购申请");} else {System.out.println("金额过大,需要董事会讨论");}}
}// 请求类
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;}
}// 客户端类
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).setSuccessor(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);}
}
主要改动点:
- 在
Approver
抽象类里,把setSuccessor
方法的返回值类型改成了Approver
,并让它返回this
。 - 客户端代码中的责任链设置从原来的逐行调用转变为链式调用,极大地提升了代码的可读性。
注意事项:
- 链式调用的本质是,后一个处理者会覆盖前一个处理者设置的
successor
。在这个例子中,真正生效的责任链是vicePresident -> president
。 - 要构建正确的责任链,应该按照
director -> manager -> vicePresident -> president
这样的顺序来设置。你可以通过以下方式实现:
director.setSuccessor(manager);
manager.setSuccessor(vicePresident);
vicePresident.setSuccessor(president);
二、return this;返回的是谁?
在责任链模式的代码里,return this;
返回的是当前正在执行setSuccessor
方法的处理者实例。下面结合具体例子详细说明:
1. setSuccessor
方法的返回值
在Approver
抽象类中,setSuccessor
方法经过修改后返回this
:
public Approver setSuccessor(Approver successor) {this.successor = successor;return this; // 返回当前处理者实例
}
this
的含义:在某个具体处理者(像Director
、Manager
等)调用setSuccessor
方法时,this
指的就是该处理者对象。
2. 链式调用的执行流程
来看客户端代码里的链式调用:
director.setSuccessor(manager).setSuccessor(vicePresident).setSuccessor(president);
执行步骤如下:
⑴.director.setSuccessor(manager)
- 把
manager
设为director
的下一个处理者。 - 返回
director
对象(也就是this
)。
⑵.setSuccessor(vicePresident)
- 由于第一步返回的是
director
,所以这里实际上是director.setSuccessor(vicePresident)
。 - 这就会覆盖掉
director
原来的successor
(原本是manager
),将其更新为vicePresident
。 - 再次返回
director
对象。
⑶.setSuccessor(president)
- 同理,这里是
director.setSuccessor(president)
。 - 又一次覆盖
director
的successor
,现在变成了president
。 - 还是返回
director
对象。
3. 最终形成的责任链
经过上述链式调用后,责任链的结构是:
director → president
- 问题所在:
manager
和vicePresident
被排除在了责任链之外,这显然不是我们期望的结果。
4. 正确构建责任链的方法
要构建director → manager → vicePresident → president
这样正确的责任链,应该依次设置每个处理者的下一个处理者:
director.setSuccessor(manager); // director 的下一个是 manager
manager.setSuccessor(vicePresident); // manager 的下一个是 vicePresident
vicePresident.setSuccessor(president); // vicePresident 的下一个是 president
5.总结
return this
的作用:它使得方法可以被链式调用,但在构建责任链时,必须谨慎使用,保证每个处理者的successor
设置正确。- 常见错误:直接链式调用
setSuccessor
会导致前面设置的successor
被覆盖,就像例子中最后只有director → president
这一条链路。
三、successor被覆盖是什么意思?
在责任链模式中,"successor 被覆盖" 指的是在设置处理者链时,由于错误地使用链式调用,导致先前设置的下一个处理者(successor)被后续操作意外替换的情况。以下通过具体示例详细解释:
1. 正确的责任链设置
责任链模式要求每个处理者的successor
指向下一个正确的处理者。例如:
director.setSuccessor(manager); // director → manager
manager.setSuccessor(vicePresident); // manager → vicePresident
vicePresident.setSuccessor(president); // vicePresident → president
此时的责任链结构为:
director → manager → vicePresident → president
2. 错误的链式调用导致覆盖问题
如果误用链式调用,例如:
director.setSuccessor(manager).setSuccessor(vicePresident).setSuccessor(president);
执行过程分解:
-
director.setSuccessor(manager)
director
的successor
被设为manager
。- 方法返回
director
(即this
)。
-
.setSuccessor(vicePresident)
- 由于返回的是
director
,实际执行的是director.setSuccessor(vicePresident)
。 - 覆盖了第一步设置的
successor
,现在director
的successor
变成vicePresident
,manager
被排除。
- 由于返回的是
-
.setSuccessor(president)
- 同理,执行
director.setSuccessor(president)
。 - 再次覆盖,
director
的successor
最终变为president
,vicePresident
也被排除。
- 同理,执行
最终责任链结构:
director → president
中间的manager
和vicePresident
被完全跳过,这就是 **"successor 被覆盖"** 的结果。
3. 为什么会被覆盖?
-
return this
的副作用:
在链式调用中,每次调用setSuccessor
都返回当前处理者(如director
),导致后续的setSuccessor
总是作用于同一个处理者(如director
),从而覆盖之前的设置。 -
正确链式调用的写法:
如果要使用链式语法,必须确保每次调用返回不同的处理者:
director.setSuccessor(manager); // 返回 director(忽略)
manager.setSuccessor(vicePresident); // 返回 manager(忽略)
vicePresident.setSuccessor(president); // 返回 vicePresident(忽略)
这种写法虽然语法上是链式的,但实际是分步骤设置不同处理者的 successor,避免覆盖。
相关文章:
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...