【问题标题】:How do I create "undo" in C++?如何在 C++ 中创建“撤消”?
【发布时间】:2011-02-14 07:43:15
【问题描述】:

我需要创建一个函数来撤消上一个任务/添加/更改。我如何在 Borland C++ 中做到这一点?

(程序使用“列表”将文本字符串存储在文本文件中。除非我使用我创建的保存功能,否则它会被存储然后擦除。)

顺便说一下,我的意思是在一个简单的控制台应用程序中创建一个撤消功能。

【问题讨论】:

    标签: c++ function undo borland-c++


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      您可以存储状态快照。状态是动作可以修改的数据集。单击撤消时,当前状态将替换为先前状态。实际上,这不是一项简单的任务,尤其是在状态复杂的情况下。

      【讨论】:

        【解决方案3】:

        另见纪念品图案。有时,撤消操作的命令中必须包含的情报非常复杂。例如,在绘图程序中绘制对象。只存储一个备忘录然后从该备忘录恢复以实现撤消会更容易。

        【讨论】:

          【解决方案4】:

          要实现撤消,您需要在应用程序中创建一个“操作堆栈”。不过,有两种基本方法:

          1. 了解您的基线(上次保存文件或创建文件后),记住所做的每一个更改,以便在需要撤消某些事情时,您只需丢弃“最顶层" 项目并从基线和所有更改重新生成当前视图。单击“重做”,然后将该项目放回堆栈。这有一个附带好处,即能够在堆栈中的任何位置轻松删除项目,而不会弄乱其他撤消/重做选项,尽管需要特别注意确保“更高”状态的应用符合用户的预期。

          2. 对于每个操作,存储对先前状态所做的更改以及在您要撤消时恢复先前状态所需的更改。现在,当用户单击“撤消”时,只需执行“撤消”步骤。单击“重做”时,重新应用所做的更改。在某些情况下,“撤消”步骤将是“这就是以前的样子”,但是如果您希望允许用户删除不在堆栈顶部的项目然后需要删除上面的某些内容,这可能会造成严重破坏它。

          正确的选择取决于很多因素,包括您可以/将携带多少数据。选项 #1 在某种意义上更容易,但如果操作堆栈很大,撤消任何操作可能会变得非常慢。

          【讨论】:

          • 看来你在这个问题上的票数超过了你,但我喜欢你的思路。尤其是您是唯一一个考虑过要撤消不在堆栈顶部的东西的问题,这远非微不足道!
          • 谢谢,是的,其他回复指出了模式,但实际上并没有讨论它们。这一切都很好,但我不喜欢尝试将模式与问题相匹配作为起点。通常(对我来说,使用 TDD)它以另一种方式工作;一旦达到解决方案,就会显示出一种模式。
          【解决方案5】:

          我会再给出一个答案,但我认为到目前为止覆盖范围还不够。

          这个主题远非微不足道,谷歌搜索它会返回大量结果。许多应用程序都实现了“撤消”操作,并且有很多变体。

          这里有两种设计模式可以帮助我们:

          • Command:这是一个动作的具体化
          • Memento: 包括存储状态(通常意味着某种形式的序列化)

          Command 模式在图形环境中被大量使用,因为通常有多种方法可以完成一个动作。以 Microsoft Word 中的 save 为例:

          • 您可以点击保存图标
          • 您可以进入文件菜单并点击保存
          • 您使用快捷方式,通常是 CTRL+S

          当然 save 可能是按照 save as 来实现的。

          Command 模式的优势是双重的:

          • 您可以创建一堆对象
          • 您可以要求每个对象实现undo 操作

          现在,undo 存在各种问题:

          • 某些操作无法撤消(例如,考虑 Linux 上的 rm 或 Windows 上的 清空垃圾箱 操作)
          • 有些操作很难撤消,或者可能不自然(您需要存储一些状态,对象通常会被销毁,但在这里您需要将其实际存储在撤消操作的命令中)
          • 通常我们将撤消/重做视为一个堆栈,一些软件(主要是图形)建议撤消项目而不实际撤消之后所做的事情,这要实现起来要困难得多,尤其是在构建了较新的操作时要撤消的顶部...

          因为有各种各样的问题,所以有各种各样的策略:

          • 对于简单的命令,您可以考虑实现撤消(例如,添加字符可以通过删除来撤消)
          • 对于更复杂的命令,您可以考虑将撤消实现为恢复之前的状态(这就是 Memento 起作用的地方)
          • 如果您有很多复杂的命令,这可能意味着很多 Mementos 会占用空间,那么您可以使用一种方法,即每 10 或 20 个命令只记住一个 Snapshot,然后重做从最新快照到撤消命令的命令

          事实上,您可以随意混合使用CommandMemento,这取决于您的系统的具体情况以及两者的复杂性。

          我只会考虑撤消开始时执行的最后一个动作(然后使用一堆动作)。撤消用户希望的任何操作的功能要复杂得多。

          【讨论】:

            【解决方案6】:

            我最近一直在尝试这个主题。如果您不需要二进制兼容性,请查看https://github.com/d-led/undoredo-cpp

            【讨论】:

              猜你喜欢
              • 2019-05-26
              • 2017-07-26
              • 2017-10-09
              • 2013-03-05
              • 2021-06-01
              • 1970-01-01
              • 2012-04-27
              • 2023-03-23
              • 1970-01-01
              相关资源
              最近更新 更多