在没有反作用的地方保存 un-do/re-do

Saving un-do/re-do where there is no inverse action

假设我在电子表格应用程序中执行三个操作:

  1. (打开一个新的电子表格。)
  2. 在单元格 A1 中键​​入 "Hello"。
  3. 将单元格 A1 加粗。
  4. 在单元格 A2 中输入 "yellow"。

为了取消所有操作,我可以存储如下内容:

UNDO_STACK = [
    {ActiveCell: 'A1', Text: ''},      # undo for "hello"
    {ActiveCell: 'A1', Bold: false},   # undo for bold
    {ActiveCell: 'A2', Text: ''},      # undo for "yellow"
]

当然可以有更多的动作,上面的数据结构已经相当简化了。但是,我的问题是 "Replace 'e' with 'l'" 这样的复杂操作是如何工作的?我不能只保存 'action' 因为它不是完全可逆的,因为很多原始数据都丢失了。对于替换操作之类的东西,像 Excel 或 Google 工作表这样的应用程序是否需要保存 每个 已进行的替换操作?如果它是一个非常大的文件,例如 Excel 中的 500MB 文件,如果存储每个撤消操作的位置(例如,如果单元格的一半值为 NULL,我想用 '') 替换 NULL?如何以节省内存的方式保存替换操作?

大多数编辑操作都是不可逆的。例如,将单元格 A1 更改为 "hello" 的第一个操作是不可逆的,因为它会丢失该单元格中的先前文本。解决方案正如您在问题中所写:存储恢复原始状态所需的附加信息。在这种情况下,更改前单元格 A1 的内容是 ""(空字符串),因此将空字符串存储在 "undo" 对象中可以恢复旧状态。

同样,批量搜索和替换操作是不可逆的,因此它也需要足够的数据来恢复旧状态。单元格、索引和删除的子字符串的列表就足够了。如果电子表格很大并且许多单元格受到影响,则此对象可能包含大量数据;原则上你可以压缩它(例如使用像 gzip 这样的算法),但我怀疑很多应用程序会这样做。您更有可能按原样存储 "undo" 对象。您举的需要 10MB 内存来对大型电子表格进行批量编辑的示例并非不切实际,但如今 10MB 的内存也不算多。

如果 "undo" 对象需要太多内存,那么您始终可以选择不存储它,在这种情况下该操作(以及之前的任何操作)都无法撤消。在某些情况下(例如,对整个非常大的图像应用转换),撤消操作所需的信息是原始图像的完整副本,因此您可能会收到警告,提示该操作将使用大量内存并且无法撤消。如果您正在实施此操作,请确保在发生这种情况时清除整个撤消堆栈。

通常这是通过创建一个 class 或一个包含所有可能状态的对象来处理的。在您的示例中,该单元格的属性将是 StringBold (Bool). 会有一些函数可以检测到该特定对象的更改,然后有效地将其保存到保存数据的文件或内存位置直到需要为止。有趣的是,不同的软件使用这些状态的方式与您预期的不同。例如,Excel 将存储 undo 个操作,直到工作簿被保存,但如果 Excel 崩溃,它会在您恢复工作簿时尝试保留这些操作。作为参考,如果数据仅为字符串值,则具有大约 80,000 个单元格的 excel sheet 将使用大约 20Mb 的数据。在高效工作时必须牢记,您可能会有 SaveGenerate.

Save: save 方法将完全按照您的预期执行。无论设计师要求什么,它都会将您的信息的每一次更改都保存在内存中。如果你想撤销一个动作,它只会恢复到之前的保存,等等。

生成: 这个有点不同,因为它是一个已知的状态变化,可以计算撤消操作。您可以将此类型视为对象的 computed property。其中一些生成的撤消操作是显而易见的,例如,有 true/false 的粗体或非粗体操作。生成作品的其他原因可能更难以识别,例如图像的旋转。生成将是以最有效的方式处理 NULL 替换的最有效方式。您的函数仍需要为 ) 保存一些值,但内存中的一个字符优于内存中的数百或数千个字符。

总而言之,我认为您使用的可生成的撤消操作越多,它的效率就越高。几乎任何东西,除了静态数据,都有一个可以计算的逆运算,从而节省内存。从单元格 A1 到 A1:Z26 的一系列单元格的 copy/paste 可以存储为使用该确切信息的简单复制和粘贴,保存 A1 然后仅将其复制到 A1:Z26 导致戏剧性的表现将整个 A1:Z26 保存为一个动作。

我鼓励您查看这篇文章,其中包含有助于您更好地理解的重要信息:https://mynameismjp.wordpress.com/2008/12/19/undo-and-redo/