撤销和重做(Undo和Redo)的C++完美实现
矢量图软件中Undo/Redo操作

p0 et eae tl: T p rtSy e d F ea tl rD r Op rtSy y e O eae tl ra Op rS ̄ e e
c n tu t r e t AOwn r T mp n n )o e r e o srco a e( Cr e : Co o e t : v ri ; d
fn u
c n:f 曩g / 克降一个和 自 f eTi nI / o I 僦 己一样的对象
?
f n t I y o ( u e :P lB ; 叠 | u o n c i B ui s PT o t:o l | n M r MO d i n O  ̄n
口类 的定 义:
。
S ro L f S rotmRg tT on:— cT p et cB t , o th: P it j。 I
。
-
T e c nmt c s fC so o i ” D mo o t l s T u tmC nr a e
- r -
。
0po e ueS t otmRg t ̄ nt au : P i rc d r e B t o ih(o s l on V e T t
式 减 少 了类 的数 量 , 同时也更 容 易理 解。
关键 词 U d / eo n o R d ,交互设计 ,备 忘 录模 式
/ 从流中读取属性数据 /
-
q 龟 aeor; 7 裁镰辑鳖褥 SvCod / 毽r
pIcfwiD (rm.t8 l/像 性 躔 - 代e| r 奄 Se  ̄ 『m: / 存属 壹 ch e t 协 ta r e e s
| 幅 t e e w o e e Cd d帅 露 B 砸 c d m t lt ; t S S e e
Photoshop中的常用快捷键

Photoshop中的常用快捷键导言:Photoshop是一款常用的图像处理软件,它提供了许多强大的功能和工具,帮助用户创建和编辑图像。
为了提高工作效率,掌握一些常用的快捷键是非常重要的。
本文将为大家介绍一些常用的Photoshop快捷键,帮助你更快地完成工作。
一、编辑(Edit)类快捷键:1. 复制(Copy)和剪切(Cut):使用快捷键Ctrl+C和Ctrl+X进行复制和剪切操作,简化了常见的复制、剪切工作。
2. 粘贴(Paste):使用快捷键Ctrl+V进行粘贴操作,可将已复制或剪切的内容粘贴到新位置。
3. 撤销(Undo)和重做(Redo):使用快捷键Ctrl+Z和Ctrl+Shift+Z进行撤销和重做操作,帮助你回退到之前的步骤或恢复被撤销的操作。
4. 全选(Select All):使用快捷键Ctrl+A可以快速选择整个图层或文档中的内容。
5. 删除(Delete):使用快捷键Delete可以删除选中的图层或对象。
二、选择(Select)类快捷键:1. 矩形选框工具(Rectangular Marquee Tool):使用快捷键M可以快速激活矩形选框工具,帮助你选择指定区域。
2. 椭圆选框工具(Elliptical Marquee Tool):使用快捷键M并按住Shift键可以快速切换到椭圆选框工具,帮助你选择指定形状的区域。
3. 快速选择工具(Quick Selection Tool):使用快捷键W可以快速激活快速选择工具,帮助你通过画出选区来选择图像。
4. 移动工具(Move Tool):使用快捷键V可以快速切换到移动工具,帮助你移动图层或对象。
5. 提示帮助工具(Eyedropper Tool):使用快捷键I可以快速激活提示帮助工具,帮助你选择或采样图像中的颜色。
三、绘制(Painting)类快捷键:1. 画笔工具(Brush Tool):使用快捷键B可以快速激活画笔工具,帮助你绘制线条和涂抹颜色。
VSCode的代码撤销与重做操作

VSCode的代码撤销与重做操作代码编辑器是程序员日常工作中最常用的工具之一,而VSCode (Visual Studio Code)作为一款流行的开源代码编辑器,提供了许多实用的功能,其中包括代码撤销与重做操作。
本文将介绍在VSCode中如何进行代码的撤销与重做操作,以及相关的快捷键和注意事项。
一、代码的撤销操作在编写代码的过程中,我们经常需要回退到之前的某个版本,以纠正错误或者还原修改。
VSCode提供了代码的撤销操作,使程序员能够方便地回到之前的代码状态。
要进行撤销操作,可以使用以下快捷键组合:Ctrl + Z(Windows)或Cmd + Z(Mac):单次撤销,可以撤销对代码的最新修改;Ctrl + Shift + Z(Windows)或Cmd + Shift + Z(Mac):重做上一个撤销的操作,恢复被撤销的代码。
需要注意的是,撤销操作只能撤销最近的一次修改,而不能撤销多次操作。
如果需要撤销多次操作,可以多次使用撤销快捷键,或者使用撤销面板。
撤销面板是VSCode提供的一个代码撤销操作的可视化工具,可以通过以下步骤打开撤销面板:1. 点击编辑器顶部的“查看”(View)菜单;2. 在下拉菜单中选择“撤销面板”(Undo Stack)选项。
打开撤销面板后,可以看到按照时间顺序列出的被撤销的操作,同时可以点击相应的操作来进行撤销或者恢复。
二、代码的重做操作在进行撤销操作后,如果我们发现撤销的不是我们想要的结果,或者希望重新应用之前被撤销的修改,那么我们可以使用重做操作。
要进行重做操作,可以使用以下快捷键组合:Ctrl + Shift + Z(Windows)或Cmd + Shift + Z(Mac):重做上一个撤销的操作。
与撤销操作类似,重做操作也只能重做上一个撤销的操作,不能一次性重做多个操作。
如果需要重做多个操作,可以多次使用重做快捷键,或者使用重做面板。
重做面板是VSCode提供的一个代码重做操作的可视化工具,可以通过以下步骤打开重做面板:1. 点击编辑器顶部的“查看”(View)菜单;2. 在下拉菜单中选择“重做面板”(Redo Stack)选项。
MySQL中的redolog和undolog日志详解

MySQL中的redolog和undolog⽇志详解MySQL⽇志系统中最重要的⽇志为重做⽇志redo log和归档⽇志bin log,后者为MySQL Server层的⽇志,前者为InnoDB存储引擎层的⽇志。
1 重做⽇志redo log1.1 什么是redo logredo log⽤于保证事务的持久性,即ACID中的D。
持久性:指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发⽣故障也不应该对其有任何影响。
redo log有两种类型,分别为物理重做⽇志和逻辑重做⽇志。
在InnoDB中redo log⼤多数情况下是⼀个物理⽇志,记录数据页⾯的物理变化(实际的数据值)。
1.2 redo log的功能redo log的主要功能是⽤于数据库崩溃时的数据恢复。
1.3 redo log的组成redo log可以分为以下两部分存储在内存中的重做⽇志缓冲区存储在磁盘上的重做⽇志⽂件1.4 记录redo log的时机在完成数据的修改之后,脏页刷⼊磁盘之前写⼊重做⽇志缓冲区。
即先修改,再写⼊。
脏页:内存中与磁盘上不⼀致的数据(并不是坏的!)在以下情况下,redo log由重做⽇志缓冲区写⼊磁盘上的重做⽇志⽂件。
redo log buffer的⽇志占据redo log buffer总容量的⼀半时,将redo log写⼊磁盘。
⼀个事务提交时,他的redo log都刷⼊磁盘,这样可以保证数据绝不丢失(最常见的情况)。
注意这时内存中的脏页可能尚未全部写⼊磁盘。
后台线程定时刷新,有⼀个后台线程每过⼀秒就将redo log写⼊磁盘。
MySQL关闭时,redo log都被写⼊磁盘。
第⼀种情况和第四种情况⼀定会执⾏redo log的写⼊,第⼆种情况和第三种情况的执⾏要根据参数innodb_flush_log_at_trx_commit的设定值,在下⽂会有详细描述。
索引的创建也需要记录redo log。
VSCode的代码撤销与重做操作技巧

VSCode的代码撤销与重做操作技巧在编程的世界里,我们经常会遇到需要修改代码的情况。
有时候,我们可能会不小心删除了重要的代码段,或者进行了一些不想要的更改。
这时候,VSCode 中的代码撤销与重做操作就成为了我们的救星。
掌握这些操作技巧,能够大大提高我们的编程效率,减少不必要的错误和麻烦。
一、代码撤销操作代码撤销,顾名思义,就是将我们最近进行的操作取消,恢复到上一个状态。
在 VSCode 中,实现代码撤销操作非常简单。
1、快捷键最常用的方式就是使用快捷键“Ctrl +Z”(Windows 和Linux 系统)或者“Command +Z”(Mac 系统)。
无论您是删除了一段代码、修改了一行语句,还是进行了其他的编辑操作,只要按下这个组合键,就能快速撤销上一步的操作。
2、菜单栏操作如果您不喜欢使用快捷键,也可以通过菜单栏来实现代码撤销。
点击顶部菜单栏中的“编辑”选项,在下拉菜单中就能看到“撤销”选项,点击即可撤销上一步操作。
3、多次撤销有时候,我们可能需要撤销不止一步的操作。
在 VSCode 中,您可以连续多次按下“Ctrl +Z”或“Command +Z”来逐步撤销之前的多个操作,直到达到您想要的状态。
二、代码重做操作当我们撤销了一些操作后,发现撤销得过多或者撤销错了,这时候就需要用到代码重做操作。
1、快捷键与撤销操作相对应,代码重做的快捷键是“Ctrl +Y”(Windows 和Linux 系统)或者“Command + Shift +Z”(Mac 系统)。
2、菜单栏操作同样,在菜单栏的“编辑”选项中,找到“重做”选项,点击即可重做上一步撤销的操作。
三、注意事项1、撤销范围需要注意的是,代码撤销和重做操作通常只对当前打开的文件有效。
如果您在多个文件中进行了操作,撤销和重做只会影响当前处于活动状态的文件。
2、保存与未保存在未保存的情况下进行的操作,撤销和重做功能仍然有效。
但是,如果您关闭了未保存的文件,那么之前未保存的撤销和重做历史将会丢失。
多次撤销操作实现uml与设计模式

多次撤销操作实现uml与设计模式【原创实用版】目录1.UML 与设计模式的关系2.多次撤销操作的实现方法3.UML 类图的撤销和重做功能4.设计模式的应用5.总结正文【1.UML 与设计模式的关系】UML(Unified Modeling Language,统一建模语言)是一种用于描述、可视化、构建和文档化软件系统的标准化建模语言。
设计模式则是一种在软件设计中的优秀解决方案,它是对在某种环境下共享的面临某种问题的解决方案。
UML 与设计模式在软件开发过程中相辅相成,可以帮助开发者更好地理解和设计软件系统。
【2.多次撤销操作的实现方法】在实际软件开发中,我们需要实现一个功能,即用户可以多次撤销操作。
为了实现这个功能,我们可以采用以下方法:1) 保存每个操作前的状态,当需要撤销时,回溯到上一个状态。
2) 使用堆栈数据结构,将每个操作记录在堆栈中,当需要撤销时,从堆栈中弹出对应的操作并执行逆操作。
3) 使用版本号机制,每次操作更新版本号,当需要撤销时,回退到上一个版本号对应的状态。
【3.UML 类图的撤销和重做功能】在 UML 类图中,我们可以通过添加操作来实现撤销和重做功能。
具体来说,可以添加两个操作:一个是撤销操作(如 undo),另一个是重做操作(如 redo)。
撤销操作用于撤销上一次操作,重做操作用于重新执行上一次操作。
通过这种方式,用户可以自由地撤销和重做操作,实现多次撤销功能。
【4.设计模式的应用】在实现多次撤销操作的功能时,我们可以采用设计模式来优化代码结构和提高代码复用性。
例如,可以使用命令模式来封装每次操作,将操作的记录和执行逻辑分离。
这样,在实现撤销和重做功能时,只需要修改命令对象对应的实现逻辑,而无需修改其他部分代码。
【5.总结】通过使用 UML 与设计模式,我们可以更好地理解和设计软件系统。
在实现多次撤销操作的功能时,我们可以采用保存状态、堆栈数据结构和版本号机制等方法。
回退段和重做日志缓冲区的区别和联系
回退段和重做日志缓冲区的区别和联系一直被回退段和重做日志缓冲区所困扰,现在总算有些明白,现在总结一下,其中的错误请大家指正。
从名字上看就可以看出回退段主要用于UNDO的,而重做日志缓冲区主要用于REDO的。
Oracle崩溃恢复步骤如下:首先rolling forward 前滚:由于oracle failure,sga中的内存信息丢失了,但是online redo log 中还是存储了transaction信息,包括commited or uncommited data。
可能这些修改信息并没有被oracle正确的来处理,包含两种情况:已经提交的还没有写入数据文件,或者没有提交的却被写入了数据文件。
针对已经提交的还没有写入数据文件就要发生前滚,在前滚过程中,smon会根据online redo log中的记录来完成对datafile的修改。
保证已经提交的数据已经写入数据文件。
(SMON负责系统监视已经一些系统清理及恢复工作,这些工作主要包括:1.清理临时空间以及临时段SMON负责在数据库启动时清理临时表空间中的临时段,或者一些异常操作过程遗留下来的临时段,例如,当创建索引过程中,创建期间分配给索引的Segment被标志为TEMPORARY,如果Create Index (或rebuild Index等)会话因某些原因异常中断,SMON负责清理这些临时段。
2.接合空闲空间在DMT(字典管理表空间)中,SMON负责把那些在表空间中空闲的并且互相是邻近的Extent接合成一个较大的空闲扩展区,这需要表空间的pctincrease设置为非零值。
3.执行实例恢复(Instance recovery)在实例恢复过程中,SMON的工作包括三个环节:应用Redo执行前滚、打开数据库提供访问、回滚未提交数据)接下来,前滚结束后,数据库正常open,此时用户可以正常连接,可以访问已经recover 的commited data,但是对于那些属于unrecoverable transaction的uncommited data,会被oracle 加锁,是不可以访问的。
数据库工程师复习重点:故障管理
数据库工程师复习重点:故障管理故障管理11.1 事务1、事务是数据库的逻辑控制单位,是操作数据的一个程序执行单元。
2、为了保证数据的完整性,要求数据库系统维护事务具有如下性质:(1) 原子性:事务是一个不可分割的工作单位,事务中的操作要么都做,要么都不做;(2) 一致性:事务执行的结果必须使数据库从一个一致的状态变到另一个一致的状态;(3) 隔离性:一个事务内部的操作及使用的数据对于其他并发事务是隔离的;(4) 持续性:一个事务提交后,它对数据库中数据的改变是永久性的,即使系统可能出现故障,也不会对其它执行的结果有任何影响。
11.2 故障的种类及解决方法11.2.1 事务内部故障1、预期的事务内部故障:通过事务程序本身发现的事物内部故障,可以通过将事务回滚,撤销其对数据库的修改,从而使数据库回到一致性的状态;2、非预期的事务内部故障:(1)由于事务内部故障大部分属于此类,所以事务故障仅限指此类故障;(2)事务故障表明事务没有提交或撤销就结束了,因此数据库可能处于不正确的状态,因此,恢复事务必须强行回滚事务,在保证该事务对其他事务没有影响的条件下,利用日志文件撤销其对数据库的修改,使数据库恢复到该事务运行之前的效果;(3)事务故障恢复是由系统自动完成的,对用户是透明的。
11.2.2 系统故障(软故障)1、指数据库在运行过程中,由于硬件故障、数据库软件及操作系统的漏洞、突然停电等情况,导致系统停止运转,所有正在运行的事务以非正常方式终止,需要系统重新启动的一类故障;2、系统故障导致内存中的内容丢失,而在硬盘上的内容仍然完好;从而导致数据库的数据可以处于不正确的状态;3、要消除这些事务对数据库的影响,保证数据库中数据的一致性,办法就是在计算机系统重新启动后,对于未完成的事务可能已经写入数据库的内容,回滚所有未完成的事务写的结果,以保证数据库中数据的一致性;对于已完成的事务可能部分或全部留在缓存区的结果,需要重做所有已提交的事务,以将数据库真正恢复到一致状态。
undo语句
"Undo" 是一个通常用于数据库和某些应用程序中的术语,用于撤销之前执行的操作。
当用户或系统执行了一个操作(例如,删除一个文件或更改数据库中的数据),并且想要撤销该操作时,"undo" 功能允许他们返回到操作之前的状态。
在数据库中,"undo" 通常与事务一起使用。
事务是一系列操作,要么全部成功,要么全部失败。
如果事务中的某个操作失败,可以使用"undo" 来撤销该操作,使数据库回到事务开始之前的状态。
例如,考虑一个简单的银行转账场景:1.用户A 想要从其账户中转账100美元给用户B。
2.数据库执行以下操作:从用户A 的账户中减去100美元,向用户B 的账户中增加100美元。
3.如果在转账过程中发生错误,例如网络中断或系统故障,那么整个转账事务可能会失败。
此时,"undo" 可以撤销从用户 A 的账户中减去100美元的操作,并确保这100美元仍然在用户 A 的账户中。
在某些应用程序中,"undo" 也可以用于撤销用户在界面上执行的操作,例如删除一个文件或移动一个文件。
要实现"undo",通常需要使用一个撤销栈(undo stack)。
当一个操作被执行时,它会被推入这个撤销栈中。
如果需要撤销操作,可以从撤销栈中弹出该操作并执行其相反的操作。
需要注意的是,"undo" 和"redo" 是相反的概念。
"redo" 是用于重新执行之前执行的操作,通常在事务回滚后使用,以确保数据的一致性。
2022年西南大学数据科学与大数据技术专业《数据库系统原理》科目期末试卷A(有答案)
2022年西南大学数据科学与大数据技术专业《数据库系统原理》科目期末试卷A(有答案)一、填空题1、安全性控制的一般方法有____________、____________、____________、和____________视图的保护五级安全措施。
2、关系规范化的目的是______。
3、数据库内的数据是______的,只要有业务发生,数据就会更新,而数据仓库则是______的历史数据,只能定期添加和刷新。
4、若事务T对数据对象A加了S锁,则其他事务只能对数据A再加______,不能加______,直到事务T释放A上的锁。
5、事务故障、系统故障的恢复是由______完成的,介质故障是由______完成的。
6、____________、____________、____________和是计算机系统中的三类安全性。
7、在SELECT命令中进行查询,若希望查询的结果不出现重复元组,应在SEL ECT语句中使用______保留字。
8、在数据库系统封锁协议中,一级协议:“事务在修改数据A前必须先对其加X锁,直到事务结束才释放X锁”,该协议可以防止______;二级协议是在一级协议的基础上加上“事务T在读数据R之前必须先对其加S锁,读完后即可释放S锁”,该协议可以防止______;三级协议是在一级协议的基础上加上“事务T在读数据R之前必须先对其加S锁,直到事务结束后才释放S锁”,该协议可以防止______。
9、SQL语言的数据定义功能包括______、______、______和______。
10、在VB 6.0中,已经用Adobel连接到数据库,并已绑定到数据库中的某个关系表,现要通过此控件向表中插入数据,需要用到Adobel.Recordset的_____方法和Update方法,使用Adobel.Recordset的_____方法可以使当前行指针在结果集中向前移动一行。
二、判断题11、在SQL中,ALTERTABLE语句中MODIFY用于修改字段的类型和长度等,ADD用于添加新的字段。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
器和算法 来实现需要的功能。 首先看看三个基本操作的原始实现: #endif ///////////////////////////////////////////////////////////////////// /////////// //三个基本操作的初始代码实现 #include <iostream> #include <map> //对象类 class Object { public: Object():_member(0){} Object(int m):_member(m){} private: int _member; }; int main() { typedef std::map<int,Object> MAP; MAP m;//必须用这个容器来表示对象的存在状态,并且可以根 据标识符得到对象 //首先创建两个 Object 对象,为了避免指针的出现,采用了 标识号的方法 {//创建操作的撤销和重做 int id1=1,id2=2;//两个对象的标识号创 建参数保存于此 Object obj(10);//对象创建参数保存于此 m.insert(std::make_pair(id1,obj));// 创建标识号为 id1 的对象 m.insert(std::make_pair(id2,obj));// 创建标识号为 id2 的对象 //创建操作的撤销非常容易实现 m.erase(id1);//创建标识号为 id1 的对象 的撤销操作 m.erase(id2);//创建标识号为 id2 的对象 的撤销操作 //创建操作的重做操作也非常容易实现, 不 过需要备份的创建参数 m.insert(std::make_pair(id1,obj));// 重做创建标识号为 id1 的对象 m.insert(std::make_pair(id2,obj));// 重做创建标识号为 id2 的对象
一定已经存在了 ///////////////////////////////////// //////////////////// int id1=1,id2=2;//两个对象的标识号创 建参数保存于此 Object obj(10);//对象创建参数保存于此 m.insert(std::make_pair(id1,obj));// 创建标识号为 id1 的对象 m.insert(std::make_pair(id2,obj));// 创建标识号为 id2 的对象 ///////////////////////////////////// //////////////////// //下面才能够开始实现删除操作 //为了能够实现撤销操作而必须保存的信 息 Object OBK1 = m[id1];//备份标识号为 id1 的对象的原始信息 Object OBK2 = m[id2];//备份标识号为 id2 的对象的原始信息 //开始对对象实现删除操作 m.erase(id1);//删除标识号为 id1 的对象 m.erase(id2);//删除标识号为 id2 的对象 //开始对对象实现撤销操作 m.insert(std::make_pair(id1,OBK1));// 创建标识号为 id1 的对象 m.insert(std::make_pair(id2,OBK2));// 创建标识号为 id2 的对象 //开始对对象实现重做操作 m.erase(id1);//重做删除标识号为 id1 的 对象 m.erase(id2);//重做删除标识号为 id2 的 对象 } {//复合操作 //由于复合操作需要对三个基本操作进行 保存,也需要对子复合操作 //进行保存,在这里不方便给出,所以在后 续的章节对这三个基本操 //作进行了封装之后才能够讨论。 } return 0; } ///////////////////////////////////////////////////////////////////// ///////////
} {//修改操作的撤销和重做 //当然如果需要修改操作的话, 对象就必须 一定已经存在了 ///////////////////////////////////// //////////////////// int id1=1,id2=2;//两个对象的标识号创 建参数保存于此 Object obj(10);//对象创建参数保存于此 m.insert(std::make_pair(id1,obj));// 创建标识号为 id1 的对象 m.insert(std::make_pair(id2,obj));// 创建标识号为 id2 的对象 ///////////////////////////////////// //////////////////// //下面才能够开始实现修改操作 //为了能够实现撤销操作而必须保存的信 息 Object OBK1 = m[id1];//备份标识号为 id1 的对象的原始信息 Object OBK2 = m[id2];//备份标识号为 id2 的对象的原始信息 //为了能够实现重做操作而必须保存的信 息 Object OM1(20);//备份标识号为 id1 的对 象的修改参数信息 Object OM2(50);//备份标识号为 id2 的对 象的修改参数信息 //开始对对象实现修改操作 m[id1] = OM1;//修改标识号为 id1 的对象 m[id2] = OM2;//修改标识号为 id2 的对象 //开始对对象实现撤销操作 m[id1] = OBK1;//撤销修改标识号为 id1 的对象 m[id2] = OBK2;//撤销修改标识号为 id2 的对象 //开始对对象实现重做操作 m[id1] = OM1;//重做修改标识号为 id1 的 对象 m[id2] = OM2;//重做修改标识号为 id2 的 对象 } {//删除操作的撤销和重做 //当然如果需要删除操作的话, 对象就必须
#if 0 从代码中可以看出,为了表示对象的创建和删除,必须用另外一个 map 容器来表示,当 容器中有指定标识号的对象存在时,表示对象被创建了;当容器中没有指定的标 识号的对象 存在时,则表示对象被删除了。很明显,表示对象的存在状态必须通过另外的方 式来表达, 在本文中采用的是 STL 中的 map 容器,因为该容器有很方便的查找功能,另外也 是和我们需要 的用标识符作为关键字来查询对象的概念的。 因此后续的文档中都会以 map 容器 为基础进行 容器演变。 本章完! 在下一章里面将会对这三个基本命令进行总结封装, 并进一步的实现了 复合操作的封装 。有了复合操作的封装之后,才可以更深入的讨论撤销和重做机制的其它内容。 (敬请关注 )。
仿函数保 存反操作 的方法
从上面的撤销和重做方案中我们可以看出共同的毛病, 撤销和重做机态信息,在撤销 的时候就用这个备份的状态信息修改应用程序的当前状态, 从而达到了撤销的功能, 同样为 了能够实现重做功能, 也需要在重做之前备份应用程序的状态信息, 在重做的时候使用这个 备份的状态信息修改应用程序的当前状态,从而达到了重做的功能。 虽然大多数应用程序中都有撤销和重做的功能, 但是仍然有许多的程序没有撤 销和重做的功能,即使有也非常弱,原因当然是撤销和重做功能不易实现的原因了。 好了, 对我所知道的这些撤销和重做的方案经过分析之后, 可以看出比较理想 的是最后一种,即:仿函数保存反操作的方法,但是这里面需要写非常多的反操作。为了减 少书写反操作的代码, 自己的方案里面采用和仿函数保存反操作类似的方法, 但是又没有大 量书写反操作的麻烦, 同时代码组织非常简洁 (通常来说撤销和重做机制可以以库的形式提 供, 使用该库的你仅仅只需要用仅有的几个封装的非常完美的操作来表达你的任意操作即可。 这种表达方式和一般的编码过程非常类似,因而就不需要考虑反操作的问题)。这将在本系 列的后续文章中详细讨论!(敬请关注)
撤销和重做的方案优点和缺点 撤销和重 做方案 将整个应 用程序的 状态序列 化到文件 自定义 分配器管 理内存池 的方法 优点和缺点 撤销和重做的步骤数量一般不多,最常见的是只能够撤销和重做一 步,因为步骤多了会占用非常多的磁盘空间,同时撤销和重做的操作 消耗时间也非常多,但是代码组织却非常简单 有着非常复杂的内存分配算法,代码不容易理解,使用也有点不方 便,方法和上面的序列化方案类似,只不过序列化到了内存中,代码 组织也非常简单 用仿函数保留每一步操作所对应的反操作,虽然占用的内存空间不 大,操作消耗的时间也不多,但是为每一步操作都必须写出相应的反 操作是一个非常繁重的任务,况且一些操作还不一定存在着反操作, 因此必然导致采用其它的方法进行补充那些没有反操作或者即使有 反操作,但是反操作也很难写出的情况。虽然有了时间和空间上的优 点但是代码组织却比较混乱,不便于维护
撤销和重做(Undo 和 Redo)的 C++完美实现
经过一年多的时间的摸索,终于找到了一种比较完美的撤销和重做(Undo 和 Redo)的 C++实现方案,因为现在很多的应用程序都需要这种功能,所以我将我的经历写出 来让大家分享, 同时也能够让更多的人帮助我来更加完善这种架构, 同时也能够让更多的人 能够利用这种架构更好的完成它的程序。 这种架构充分利用了 STL 的容器和算法来简化代码, 因此有着比较高的正确性和可读性。 在解析我的架构之前先分析一下 (我所知道的) 目前存在的一些实现撤销和重 做的方案的优缺点。当前存在的撤销和重做的方案主要是:
#if 0 在上一篇文章中,已经对三种基本操作的撤销和重做进行了细致的分析,并给出了 示 例代码,但是并没能够给出复合操作的示例代码。这里面有着比较深刻的原因,具体来说 就是:复合操作里面保存的是三个基本操作以及子复合操作的任意组合,这里面本身就存 在一个将三个基本操作和复合操作对象化的概念,在三个基本操作实现对象化之前是不能 够讨论复合操作的!既然需要对三个基本操作进行对象化,同时还应该看到:复合操作可 以保存其它的复合操作,这说明复合操作也需要对象化!既然三个基本操作和一个复合操 作都需要对象化,并且这些对象都可以保存到复合操作里面,那么在对三个基本操作的对 象化的同时就应该考虑复合操作的对象化问题! 现在就来讨论一下三个基本操作和一个复合操作的对象化问题,不过在讨论这个问 题 之前必须先回答下面的几个问题: (1)三个基本操作和一个复合操作的组合过程需要撤销和重做功能吗? (2)三个基本操作和一个复合操作怎样保存在复合操作里面? (3)撤销和重做功能在应用程序里面是怎么使用的? 对于问题(1)可以肯定的说是不需要撤销和重做功能的, 否则就会成为“蛋鸡问题”