2014-03-24 117 views
1

在一个绘图应用程序中,我使用Memento pattern来实现多级撤销/重做。我面临的一个问题是,如果图形包含一个或多个图像对象(如我的图形对象可以嵌入base64编码的图像对象,就像Visual Studio的resx文件一样),则记忆(状态对象)将变得太大, ,由于绘图应用程序中常见的频繁鼠标操作,这将使撤销/重做堆栈很快攀升至几兆字节。为了解决这个问题,我在其中引入了gzip压缩,以便现在我将一个压缩版的纪念品保存到堆栈中。这导致整个堆栈大小减少了大约90%。实现撤销/重做

现在,这导致了另一个问题。压缩/解压缩纪念品所花费的时间在对象定位/调整大小时引入了相当大的麻烦。

解决此问题的一种方法是使用Command pattern,但我不愿走这条路,因为它会在应用程序的许多部分引入大量工作。你看到了什么其他替代品?

+2

您只能压缩比X更早的纪念品,或者随着堆栈增长,最后的Y纪念品会一直解压并压缩它们。这样,您可以快速撤消最后的Y个命令,但仍可压缩大部分历史记录以节省空间。 – poke

+1

@Poke这是一个非常有趣的想法,但是如何处理栈中存在超过Y个记忆的情况?每一次操作都会再次需要压缩一个新的对象。 –

+0

@poke:正如Samy所指出的那样,这只是在Y纪念品之后才会出现在我现在所在的同一个地方。 – dotNET

回答

2

我能想到的唯一解决方案就是不用完全切换到命令模式就可以生成一种incremental backup作为备忘录而不是使用整个对象。

这个想法是,你会从纪念品中去掉没有改变的任何数据。你只会存储差异。

进行撤消操作时,您可以使用对象的当前状态和差异来生成一个备忘录并将其注入进程中。

这里的基本上它怎么会是这样的:

  1. 看守打算做些什么来的鼻祖,但希望能够撤消更改。
  2. 看守员首先要求发件人提供纪念品。
  3. 然后它执行它将要执行的任何操作(或操作序列)。
  4. 的压缩机将比较纪念品和始发的新状态并产生将被存储在操作栈上的一个diff对象

要撤消:

  1. 的压缩机会从创始者状态和diff对象中重新创建纪念物件
  2. 然后使用新纪念碑来恢复ori ginator状态。

压缩机类的实现可能会很棘手,并取决于您将执行的操作类型。

您将使用一个单一的纪念品对象,并只存储差异对象,如果需要也可以压缩,但可能会相当小。

+0

现在这似乎是一个非常好的主意。我的纪念品是字符串(xml中的序列化对象图),所以如果我可以计算当前和以前状态的“差异”,我可以将它存储为纪念品。现在的问题是如何计算“差异”。我通过了几个有关这方面的问题,但似乎它们都是逐行处理字符串,而不是我需要的char-by-char。 – dotNET

+0

查找两个字符串之间的差异是一个众所周知的算法问题,可以找到许多解决方案。编辑距离是计算两个字符串之间差异的度量(char by char),Levenshtein距离和LCS(最长公共子序列)是这样的编辑距离,并且可以适应返回两个字符串之间的差异。 –

+0

我可以说,你不需要最好的解决方案,但一个很好的近似值。你可以把你的长字符串分成几块,然后比较它们,就好像它们是线条一样。既然你有一个XML表示,你也可以查找树比较算法。 –

1

当我在90年代在Delphi中做了类似的事情时,我拍了快照,即当堆栈/队列/列表执行大量绘制操作时,每当重绘速度过慢时,都会显示当前状态的位图。但不知道你是否可以这样做。

+0

啊不,这不是我的选择。这更像是一个矢量绘图应用程序。 – dotNET