【再谈设计模式】备忘录模式~对象状态的守护者
一、引言
在软件开发过程中,我们常常会遇到需要保存对象状态以便在之后恢复的情况。例如,在文本编辑器中,我们可能想要撤销之前的操作;在游戏中,玩家可能希望恢复到之前的某个游戏状态。备忘录模式(Memento Pattern)就为这种需求提供了一种有效的解决方案。
二、定义与描述
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。这个模式涉及到三个主要角色:
原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。
备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。
负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
三、抽象背景
在许多应用场景中,对象的状态会随着时间发生变化。然而,我们可能需要在某个特定的时间点保存对象的状态,以便后续可以撤销操作或者回到之前的某个状态。如果直接将对象的状态暴露给外部进行保存和恢复,会破坏对象的封装性。备忘录模式通过引入一个专门的备忘录对象来解决这个问题,使得对象的状态可以在不破坏封装性的情况下被保存和恢复。
四、适用场景与现实问题解决
(一)适用场景
文本编辑器的撤销/重做功能:当用户输入文字、删除文字或者进行格式调整时,每一个操作都可以看作是对象(文本内容)状态的改变。通过备忘录模式,可以轻松地保存每个操作前的文本状态,从而实现撤销和重做功能。
游戏中的存档和读档功能:游戏中的各种元素(角色属性、游戏场景等)构成了对象的状态。玩家在游戏过程中可能希望在某些关键节点保存游戏状态,之后可以随时读取之前保存的状态继续游戏。
(二)现实问题解决
以文本编辑器为例,假设我们有一个TextDocument
类作为原发器。在用户进行编辑操作(如插入字符、删除字符等)之前,我们可以创建一个备忘录来保存当前文档的状态。如果用户执行了撤销操作,我们可以从备忘录中恢复文档的之前状态。这样就可以在不破坏TextDocument
类内部结构的情况下,实现撤销功能。
五、备忘录模式的现实生活的例子
考虑拍照的过程。相机可以看作是原发器,照片就是备忘录。当我们按下快门(相当于创建备忘录)时,相机的当前状态(镜头聚焦、光圈大小、曝光设置等)被记录在照片上。我们可以将照片存储起来(相当于负责人保存备忘录),之后如果想要回顾某个瞬间(相当于恢复到之前的状态),我们可以查看对应的照片。
六、初衷与问题解决
初衷是在保持对象封装性的同时,实现对象状态的保存和恢复。通过将对象状态的保存和恢复逻辑封装在备忘录模式中,避免了外部对象直接操作对象的内部状态,从而提高了代码的可维护性和安全性。
七、代码示例
(一)Java
// 备忘录类
class Memento {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}
}// 原发器类
class Originator {private String state;public void setState(String state) {this.state = state;}public Memento saveToMemento() {return new Memento(state);}public void restoreFromMemento(Memento memento) {state = memento.getState();}
}// 负责人类
class Caretaker {private Memento memento;public void saveMemento(Memento memento) {this.memento = memento;}public Memento getMemento() {return memento;}
}public class Main {public static void main(String[] args) {Originator originator = new Originator();originator.setState("State 1");Caretaker caretaker = new Caretaker();caretaker.saveMemento(originator.saveToMemento());originator.setState("State 2");originator.restoreFromMemento(caretaker.getMemento());System.out.println(originator.state);}
}
类图:
流程图:
时序图:
(二)C++
#include <iostream>
#include <string>// 备忘录类
class Memento {
private:std::string state;
public:Memento(std::string state) : state(state) {}std::string getState() const { return state; }
};// 原发器类
class Originator {
private:std::string state;
public:void setState(std::string state) { this->state = state; }Memento saveToMemento() { return Memento(state); }void restoreFromMemento(const Memento& memento) { state = memento.getState(); }
};// 负责人类
class Caretaker {
private:Memento memento;
public:void saveMemento(const Memento& memento) { this->memento = memento; }Memento getMemento() const { return memento; }
};int main() {Originator originator;originator.setState("State 1");Caretaker caretaker;caretaker.saveMemento(originator.saveToMemento());originator.setState("State 2");originator.restoreFromMemento(caretaker.getMemento());std::cout << originator.state << std::endl;return 0;
}
(三)Python
# 备忘录类
class Memento:def __init__(self, state):self.state = statedef get_state(self):return self.state# 原发器类
class Originator:def __init__(self):self.state = Nonedef set_state(self, state):self.state = statedef save_to_memento(self):return Memento(self.state)def restore_from_memento(self, memento):self.state = memento.get_state()# 负责人类
class Caretaker:def __init__(self):self.memento = Nonedef save_memento(self, memento):self.memento = mementodef get_memento(self):return self.mementoif __name__ == "__main__":originator = Originator()originator.set_state("State 1")caretaker = Caretaker()caretaker.save_memento(originator.save_to_memento())originator.set_state("State 2")originator.restore_from_memento(caretaker.get_memento())print(originator.state)
(四)Go
package mainimport "fmt"// 备忘录结构体
type Memento struct {state string
}func NewMemento(state string) *Memento {return &Memento{state: state}
}func (m *Memento) getState() string {return m.state
}// 原发器结构体
type Originator struct {state string
}func (o *Originator) setState(state string) {o.state = state
}func (o *Originator) saveToMemento() *Memento {return NewMemento(o.state)
}func (o *Originator) restoreFromMemento(m *Memento) {o.state = m.getState()
}// 负责人结构体
type Caretaker struct {memento *Memento
}func (c *Caretaker) saveMemento(m *Memento) {c.memento = m
}func (c *Caretaker) getMemento() *Memento {return c.memento
}func main() {originator := Originator{}originator.setState("State 1")caretaker := Caretaker{}caretaker.saveMemento(originator.saveToMemento())originator.setState("State 2")originator.restoreFromMemento(caretaker.getMemento())fmt.Println(originator.state)
}
八、备忘录模式的优缺点
(一)优点
保持封装性:原发器的内部状态对外部是隐藏的,只有原发器自身能够访问备忘录中的状态,从而保护了对象的封装性。
简化撤销/恢复操作:通过备忘录模式,撤销和恢复操作可以很容易地实现,不需要在原发器中编写复杂的状态管理代码。
提供状态历史记录:可以方便地保存多个备忘录,从而形成对象状态的历史记录,这对于需要查看对象状态变化历史的应用场景非常有用。
(二)缺点
资源消耗:如果需要保存大量的备忘录,可能会消耗较多的内存资源,尤其是当备忘录对象包含大量数据时。
管理复杂度:随着备忘录数量的增加,备忘录的管理(如存储、查找、删除等)可能会变得复杂。
特性 | 描述 |
优点 | |
保持封装性 | 原发器的内部状态对外部是隐藏的,只有原发器自身能够访问备忘录中的状态,从而保护了对象的封装性。 |
简化撤销/恢复操作 | 通过备忘录模式,撤销和恢复操作可以很容易地实现,不需要在原发器中编写复杂的状态管理代码。 |
提供状态历史记录 | 可以方便地保存多个备忘录,从而形成对象状态的历史记录,这对于需要查看对象状态变化历史的应用场景非常有用。 |
缺点 | |
资源消耗 | 如果需要保存大量的备忘录,可能会消耗较多的内存资源,尤其是当备忘录对象包含大量数据时。 |
管理复杂度 | 随着备忘录数量的增加,备忘录的管理(如存储、查找、删除等)可能会变得复杂。 |
九、备忘录模式的升级版
一种常见的升级版是增加一个历史列表(History List)管理类,它可以管理多个备忘录对象,并且提供更方便的操作,如按照时间顺序查看备忘录、限制备忘录的数量以避免资源过度消耗等。例如,在文本编辑器的撤销/重做功能中,这个历史列表可以存储多个编辑操作的备忘录,并且可以方便地根据用户的操作(如多次撤销或重做)找到对应的备忘录进行状态恢复。
相关文章:
【再谈设计模式】备忘录模式~对象状态的守护者
一、引言 在软件开发过程中,我们常常会遇到需要保存对象状态以便在之后恢复的情况。例如,在文本编辑器中,我们可能想要撤销之前的操作;在游戏中,玩家可能希望恢复到之前的某个游戏状态。备忘录模式(Memento…...
算法:判断链表是否有环
/*** brief 判断链表是否有环* * 该函数使用快慢指针法来判断链表中是否存在环。* 快指针每次移动两步,慢指针每次移动一步。* 如果链表中存在环,那么快指针最终会追上慢指针;* 如果链表中不存在环,快指针会先到达链表末尾。* * p…...
Android Logcat 高效调试指南
工具概览 Logcat 是 Android SDK 提供的命令行日志工具,支持灵活过滤、格式定制和实时监控,官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用(通过ADB守…...
【数据结构与算法】Java描述:第一节:ArrayList顺序表
这篇文章我们自己实现一个顺序表, 从而更好的认识它。 一、顺序表的本质 顺序表的本质其实就是一个数组,但是在插入,查找与删除上,有些复杂,顺序表通过对方法进行封装,方便了使用。 二、自己的顺序表 2.…...
报错The default superclass, “jakarta.servlet.http.HttpServlet“(已经配置好tomcat)
报错报错DescriptionResourcePathLocationType The default superclass,“jakarta.servlet.http.HttpServlet”, according to the project’s Dynamic Web Module facet version (5.0), was not found on the Java Build Path. 解决办法: 根据错误信息࿰…...
在笔记本电脑上用DeepSeek搭建个人知识库
最近DeepSeek爆火,试用DeepSeek的企业和个人越来越多。最常见的应用场景就是知识库和知识问答。所以本人也试用了一下,在笔记本电脑上部署DeepSeek并使用开源工具搭建一套知识库,实现完全在本地环境下使用本地文档搭建个人知识库。操作过程共…...
数学建模:MATLAB极限学习机解决回归问题
一、简述 极限学习机是一种用于训练单隐层前馈神经网络的算法,由输入层、隐藏层、输出层组成。 基本原理: 输入层接受传入的样本数据。 在训练过程中随机生成从输入层到隐藏层的所有连接权重以及每个隐藏层神经元的偏置值,这些参数在整个…...
Immich自托管服务的本地化部署与随时随地安全便捷在线访问数据
文章目录 前言1.关于Immich2.安装Docker3.本地部署Immich4.Immich体验5.安装cpolar内网穿透6.创建远程链接公网地址7.使用固定公网地址远程访问 前言 小伙伴们,你们好呀!今天要给大家揭秘一个超炫的技能——如何把自家电脑变成私人云相册,并…...
Python标准库【os】5 文件和目录操作2
文章目录 8 文件和目录操作8.7 浏览目录下的内容8.8 查看文件或目录的信息8.9 文件状态修改文件标志位文件权限文件所属用户和组其它 8.10 浏览Windows的驱动器、卷、挂载点8.11 系统配置信息 os模块提供了各种操作系统接口。包括环境变量、进程管理、进程调度、文件操作等方面…...
相控阵雷达
相控阵雷达 **1. 基本概念与数学模型**(1) **阵列信号模型**(2) **波束形成原理** **2. 经典波束形成算法****(1) 常规波束形成(Conventional Beamforming, CBF)****(2) 自适应波束形成(Adaptive Beamforming)****2.1 最小方差无失…...
Java 大视界 -- 基于 Java 的大数据分布式缓存一致性维护策略解析(109)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
AI: Cursor是否已奠定AI开发环境的龙头地位?
近年来,人工智能(AI)在软件开发领域的应用迅速升温,而Cursor作为一款AI驱动的代码编辑器,凭借其创新功能和市场表现,引发了广泛讨论。许多人认为,Cursor已经奠定了AI开发环境的龙头地位。然而&a…...
PHP:IDEA开发工具配置XDebug,断点调试
文章目录 一、php.ini配置二、IDEA配置 一、php.ini配置 [xdebug] zend_extension"F:\wamp64\bin\php\php7.4.0\ext\php_xdebug-2.8.0-7.4-vc15-x86_64.dll" xdebug.remote_enable on xdebug.remote_host 127.0.0.1 xdebug.remote_port 9001 xdebug.idekey"…...
回忆Redis的持久化机制
Redis的持久化机制 前言RDB触发方式配置方式手动触发bgsave的执行流程 缺点 AOF重写机制触发方式手动触发自动触发 MP-AOF RDB和AOF混合模式 前言 大家都知道,Redis是内存数据库,也就是说client与Redis交互的过程,无论是读key还是写key都是直…...
partner‘127.0.0.1:3200‘ not reached
在SAP虚拟机中,如果LRPSAP 0显示黄色,通常表示服务启动异常或存在配置问题。以下是一些可能的处理方法: 检查主机文件配置 确保主机文件(hosts)中已正确配置SAP服务的域名解析。例如,添加以下内容到hosts文…...
网络配置的基本信息
目录 一、网络接口信息 1、关闭虚拟化服务 2、配置临时IP 3、配置静态IP 4、常见网络命令 5、安装Wireshark 一、网络接口信息 输入 ip address,会出现下面的内容 网卡名称及其含义: 网卡名称说明lo 表示本地回环地址。 ens32 有线网卡,…...
SpringBoot集成Mybatis(包括Mybatis-Plus)和日志
一、使用Mybatis 1.添加依赖 <!--Mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version> <!-- 选择与Java 8兼容的版本 --&g…...
如何在 IntelliJ IDEA 中集成 DeepSeek
如何在 IntelliJ IDEA 中集成 DeepSeek 在本教程中,我们将带您一步步完成将 DeepSeek 集成到 IntelliJ IDEA 中的过程。通过此集成,您可以在IDE中利用DeepSeek强大的功能,提高开发工作效率。 步骤 1:安装 Proxy AI 插件 首先&a…...
【自学笔记】大数据基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 大数据基础知识点总览1. 大数据概述2. 大数据处理技术3. 数据仓库与数据挖掘4. 大数据分析与可视化5. 大数据平台与架构6. 大数据安全与隐私 总结 大数据基础知识点…...
AWS ALB 实现灰度验证指南:灵活流量分配与渐进式发布
AWS Application Load Balancer (ALB) 作为七层负载均衡器,支持基于权重或内容的路由策略,是实施灰度验证(金丝雀发布)的核心工具。通过将部分流量导向新版本后端,可以安全验证功能稳定性。以下是使用 ALB 实现灰度发布的详细方案。 © ivwdcwso (ID: u012172506) 一…...
专线物流公共服务平台:全面提升专线物流效率
专线物流公共服务平台:全面提升专线物流效率 在物流行业高速发展的今天,专线物流作为物流供应链的重要环节,面临着效率低下、成本高企、信息孤岛等痛点。临沂呆马区块链网络科技有限公司(简称“呆马科技”)凭借其在大…...
行为型模式 - 观察者模式 (Publish/Subscribe)
行为型模式 - 观察者模式 (Publish/Subscribe) 又称作为订阅发布模式(Publish-Subscribe Pattern)是一种消息传递模式,在该模式中,发送者(发布者)不会直接将消息发送给特定的接收者(订阅者&…...
HTTP/2 服务器端推送:FastAPI实现与前端集成指南
HTTP/2 服务器端推送:FastAPI实现与前端集成指南 注意:本文末尾附有完整示例代码,文中仅展示核心关键代码。完整代码可在GitHub仓库获取。 本文将会讲解HTTP2协议和相关配置实践。但是不要混淆,SSE的实现完全基于HTTP/1.1的持久连…...
C++ 变量的输入输出教程
一、变量的基本概念 在 C 中,变量是用于存储数据的命名内存位置。在使用变量之前,需要先声明它的类型和名称,这样编译器才能为其分配适当大小的内存空间。例如: int age; // 声明一个整型变量 age double salary; // 声明一个…...
java作业
java作业 一. package shiyanbaogao; import java.util.Scanner; //给20块钱买可乐,每瓶可乐3块钱,喝完之后退瓶子可以换回1块钱,问最多可以喝到多少瓶可乐。请设计相应的Java程序。 public class BaoGaoDemo02 {public static void …...
LeeCode题库第四十题
40.组合总和II 项目场景: 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示…...
list的模拟实现
目录 一、构造和扩容机制 二、普通迭代器 三、const迭代器 四、tip 有了前面vetcor的基础呢,我们在学习和使用list上就更加的方便快捷,浅显易懂了,所以相似的部分我就不做过多的言语阐述了,在使用方面呢,大家可以学…...
pandas DataFrame 数据筛选与排序
数据筛选: df[df[列标签] > xxx] 使用 &(与) |(或) 拼接多个条件代码应用: &(与)应用 # 引用 pandas import pandas as pd # 定义数据 data {"产品":["男装","女装","男鞋","女鞋"…...
elpis全栈课程学习之elpis-core学习总结
elpis全栈课程学习之elpis-core学习总结 核心原理 elpis-core是全栈框架elpis的服务端内核,主要应用于服务端接口的开发以及页面的SSR渲染,elpis-core基于约定优于配置的原理,通过一系列的loader来加载对应的文件,大大节约用户的…...
零基础deep seek+剪映,如何制作高品质的视频短片
以下是专为零基础学习者设计的 剪映专业版详细教程+Deep seek配合制 ,包含从入门到精通的系统化教学,配合具体操作步骤与实用技巧: 基于DeepSeek与剪映协同制作高品质视频短片的专业流程指南(2025年最新实践版&#x…...
解决单元测试 mock final类报错
文章目录 前言解决单元测试 mock final类报错1. 报错原因2. 解决方案3. 示例demo4. 扩展 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差࿰…...
Git基本命令索引
GIT基本命令索引 创建代码库修改和提交代码日志管理远程操作操作分支 创建代码库 操作指令初始化仓库git init克隆远程仓库git clone 修改和提交代码 操作指令查看文件状态git status文件暂存git add文件比较git diff文件提交git commit回滚版本git reset重命名或者移动工作…...
非平稳时间序列分析(二)——ARIMA(p, d, q)模型
此前篇章(平稳序列): 时间序列分析(一)——基础概念篇 时间序列分析(二)——平稳性检验 时间序列分析(三)——白噪声检验 时间序列分析(四)—…...
[代码规范]接口设计规范
一个优雅的接口要如何设计?有哪些设计规范可以遵循? 下面抛砖引玉,分享一些规范。 目录 1、RESTful API 设计最佳实践 2、Shneiderman 的 8 条黄金法则 3、Nielsen 的 10 条启发式规则 1、RESTful API 设计最佳实践 一共18条,参考…...
4-3自定义加载器,并添加功能
一、自定义类加载器的实现步骤 继承ClassLoader类 自定义类加载器需继承java.lang.ClassLoader,并选择性地重写以下方法: findClass(String name):核心方法,用于根据类名查找并加载类的字节码。需从自定义路径(…...
北京大学DeepSeek提示词工程与落地场景(PDF无套路免费下载)
近年来,大模型技术飞速发展,但许多用户发现:即使使用同一款 AI 工具,效果也可能天差地别——有人能用 AI 快速生成精准方案,有人却只能得到笼统回答。这背后的关键差异,在于提示词工程的应用能力。 北京大…...
SSH密码更改
Windows User目录下的.ssh/config,全部删除 linux 在主用户文件夹,ctrlh显示隐藏文件。删除.shh文件夹内所有文件。...
蓝桥备赛(四)- 数组(下)
一 、 字符数组 1.1 介绍 数组的元素如果是字符类型 , 这种数组就是字符数组 , 字符数组可以是一维数组 , 可以是二维数组 (多维数组)。 接下来主要讨论一维的字符数组 : char arr1[5] //一维数组 char arr2[3][5] // 二维数组 C语言 中…...
基金 word-->pdf图片模糊的解决方法
1. 首先需要Adobe或福昕等pdf阅读器。 2. word中 [文件]--[打印],其中打印机选择pdf阅读器,例如此处我选择福昕阅读器。 3. 选择 [打印机属性]--[编辑]--[图像],将所有的采样、压缩均设置为 关闭。点击[另存为],保存为 基金报告…...
身为小兵,如何提升不可替代性?
之前聊过,研发、PIE、PE、可靠性等岗位,主要是对物的工作, 这类岗位,如何提升不可替代性? 我的经验是,学会识别创造性工作or重复性工作。 尽可能地做创造性工作,推重复性工作。 销售、采购、HR等岗位,主要是对人的工作, 这类岗位,如何提升不可替代性? 我的思考…...
easyExcel使用案例有代码
easyExcel 入门,完成web的excel文件创建和导出 easyExcel官网 EasyExcel 的主要特点如下: 1、高性能:EasyExcel 采用了异步导入导出的方式,并且底层使用 NIO 技术实现,使得其在导入导出大数据量时的性能非常高效。 2、易于使…...
linux服务器更新jar包脚本
【需求】Java每次发布新的版本都需要先kill掉原来的服务,然后再启动新的包 有了这个脚本只需要把包替换掉,服务会自动kill 以8184 为例 完整的脚本如下 #!/bin/bash# 检查端口 8184 是否被占用 PORT8184 PID$(lsof -t -i:$PORT)if [ -n "$PID…...
Tomcat 乱码问题彻底解决
1. 终端乱码问题 找到 tomcat 安装目录下的 conf —> logging.properties .修改ConsoleHandler.endcoding GBK (如果在idea中设置了UTF-8字符集,这里就不需要修改) 2. CMD命令窗口设置编码 参考:WIN10的cmd查看编码方式&…...
dify绑定飞书多维表格
dify 绑定飞书和绑定 notion 有差不多的过程,都需要套一层应用的壳子,而没有直接可以访问飞书文档的 API。本文记录如何在dify工具中使用新增多条记录工具。 创建飞书应用 在飞书开放平台创建一个应用,个人用户创建企业自建应用。 自定义应…...
深入浅出:插入排序算法完全解析
1. 什么是插入排序? 插入排序(Insertion Sort)是一种简单的排序算法,其基本思想与我们整理扑克牌的方式非常相似。我们将扑克牌从第二张开始依次与前面已排序的牌进行比较,将其插入到合适的位置,直到所有牌…...
MySQL--DQL、DML、DDL、DCL概念与区别
在SQL中,根据功能和操作对象的不同,通常将语文分为四大类:DQL(数据查询语言)、DML(数据操作语言)、DDL(数据定义语言)、DCL(数据控制语言) 一、D…...
【设计原则】里氏替换原则(LSP):构建稳健继承体系的黄金法则
深入理解里氏替换原则(LSP)及其在C#中的实践 一、什么是里氏替换原则?二、为什么需要LSP?三、经典违反案例:矩形与正方形问题四、正确的设计实践方案1:通过接口分离方案2:使用抽象类 五、LSP的关…...
SQL的select语句完整的执行顺序
SQL的SELECT语句的执行顺序可以用"做菜流程"来类比理解。虽然我们写SQL时按SELECT…FROM…WHERE…顺序写,但数据库执行顺序完全不同。以下是通俗易懂的讲解(附流程图和示例): 🔧 执行顺序流程图:…...
【Vue3】浅谈setup语法糖
Vue3 的 setup 语法糖是通过 <script setup> 标签启用的特性,它是对 Composition API 的进一步封装,旨在简化组件的声明式写法,同时保留 Composition API 的逻辑组织能力。以下是其核心概念和原理分析: 一、<script setu…...
算法-二叉树篇27-把二叉搜索树转换为累加树
把二叉搜索树转换为累加树 力扣题目链接 题目描述 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提…...