2009-11-28 59 views
6

我读在article撤消/恢复与不可改变的对象

不可变对象下面特别 方便用于实现某些共同 成语如撤消/重做,可中止 交易。以撤消为例。 A 用于实现撤销 的常用技术是保持一堆对象,该对象以某种方式知道如何以反向方式运行每个命令 (所谓的“命令 模式”)。然而,弄清楚如何 反向运行一个命令可以是 棘手。更简单的技术是在连续的命令之间维护表示系统 的状态的不可变对象堆栈 。然后, 撤消命令,你只需恢复 到以前的系统状态(和 可能存储在 重做堆栈中的当前状态)。

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

回答

6

不可变对象将保存系统的整个状态,因此在这种情况下,您将拥有包含原始收件箱的对象A,然后包含收件箱并包含十封电子邮件的对象B被删除,效果)从B指向A的指针,表示如果您执行一个“撤消”操作,则停止使用B作为系统状态,并开始使用A代替。

然而,Gmail收件箱都过于庞大使用这种技术。您可以将它用于实际可以存储在相当少量内存中的文档,以便您可以保留其中的很多文档以进行多级撤消。

如果您想保留10个撤消级别,只需保留两个不可变的对象(一个是当前的,一个是从十个“撤消”前的)和一个已应用的命令列表它们之间。

做一个“撤销”,重新执行所有,但最后一个命令对象,用它作为新的当前对象,并删除最后一个命令(或将其保存为“重做”的对象)。每次执行新操作时,都会更新当前对象,将相关的命令添加到列表中,然后(如果列表的长度超过十个命令),则从撤消列表的起始处对对象执行第一个命令并扔掉列表上的第一个命令。

你可以做其他各种的检查点系统,以及涉及可变数量的系统的完整表述的,以及命令它们之间的可变数目。但是,它越来越远离你引用的原始思想,变得越来越像一个典型的可变系统。但是,它确实避免了使命令始终可逆的问题;你只需要将Commands应用到一个对象而不是反向。

SVN和其它版本控制系统是有效的撤销和 - 重做的盘状或基于网络的形式。

+3

“Gmail收件箱太大而无法使用此技术”。伊什。如果实际消息是单独的对象,并且两个不同的收件箱对象引用相同的消息,则收件箱只是一个列表,您可能可以这样做。关于不可变对象的另一件好事是对象可以像这样安全地共享资源。使用可变对象时,您可能不得不担心对另一个中出现错误的变化。 – 2009-11-28 18:03:54

+1

这是一个很好的观点。我注意到,对于GMail帐户,适当的不可变对象将是每个标签的标签列表和电子邮件对象的关联列表;这比整个存档小得多,但比收件箱邮件列表大得多。 – jprete 2009-11-30 18:49:53