使用不可变对象撤消/重做

时间:2009-11-28 16:41:24

标签: language-agnostic undo-redo immutability

我在article

中阅读了以下内容
  

特别是不可变对象   方便实施某些共同点   诸如撤销/重做和流产之类的习语   交易。以撤消为例。一个   实现撤消的常用技术   是保持一堆对象   不知何故知道如何运行每个命令   反过来(所谓的“命令”   模式“)。然而,弄清楚如何   反向运行命令即可   棘手。一种更简单的技术是   维护一堆不可变对象   代表系统的状态   连续命令之间。然后,到   撤消命令,只需还原即可   到以前的系统状态(和   可能存储当前状态   重做堆栈。)

但是,文章没有展示如何使用不可变对象来实现“撤销”操作的一个很好的实际例子。例如...从Gmail收件箱中删除10封电子邮件。一旦你这样做,它有一个撤消选项。在这方面,不可变对象如何帮助?

1 个答案:

答案 0 :(得分:6)

不可变对象将保持系统的整个状态,因此在这种情况下,您将拥有包含原始收件箱的对象A,然后包含删除了10封电子邮件的收件箱的对象B(实际上) )一个从B回到A的指针,表示如果你做一个“撤销”,那么你就停止使用B作为系统状态并开始使用A代替。

但是,Gmail收件箱太大而无法使用此技术。您可以在实际存储在相当少量内存中的文档中使用它,这样您就可以将其中的许多内容保留在多级撤消中。

如果你想保持十级撤消,你可以通过只保留两个不可变对象来保存内存 - 一个是最新的,一个是10个“undos”前 - 以及一个在两个之间应用的命令列表。它们。

要执行“撤消”,您将重新执行除最后一个Command对象之外的所有对象,将其用作新的当前对象,并擦除最后一个Command(或将其另存为“Redo”对象)。每次执行新操作时,都会更新当前对象,将关联的命令添加到列表中,然后(如果列表长度超过十个命令),则从撤消列表的开头执行对象上的第一个命令并扔掉名单上的第一个命令。

您还可以执行各种其他检查点系统,包括系统的可变数量的完整表示以及它们之间的可变数量的命令。但它越来越远离你引用的原始想法,变得越来越像一个典型的可变系统。但是,它确实避免了使命令始终可逆的问题;您只需将命令应用于对象前进而不是反向。

SVN和其他版本控制系统实际上是基于磁盘或网络的撤消和重做形式。