基本思想就是备份。
把你做更改之前的东西先存起来,然后再改。如果你想恢复,就把原来的那个再弄回来。
这个实际上还有很多复杂之处。
比如是要支持无际次的撤销,还是只能撤销最后一次的操作。这两个设计的复杂度,本质上很有区别。主要是看需要,如果应用本身不复杂,只支持一次撤销就可以很好地避免按错键,或不慎引发的错误操作。如果应用很复杂,很可能就需要支持多次的撤销。
如果支持多次撤销,连续的几个改动应该算一次操作一起记录在一个事件中呢,还是分开记。这要靠逻辑,主要是看用户一次想恢复什么东西,设计的时候要慎重。既不要让人为了恢复上次的状态,必须做数次撤销。也不要一次恢复的太多,让人无法使用。
另外就是要考虑“撤销”这个动作本身是否可以撤销,一般来说有个重做(redo)操作就可以满足应用。但复杂的时候只这样不行,因为更改很可能不是线性的。
比如现在处于状态一,之后改成了状态二,然后改成了状态三。这时我的想法变了,撤销回了状态二,之后又改成了状态四。我的想法又变了,这时我做一次撤销来到状态二,再做一次撤销时是不是应该回到状态一呢?但如果我想回复到状态三呢?
另外如果支持无限撤销的话,很有可能因为备份数据浪费很多内存。
是否应该为了节约资源,而在超过一定额度的内存使用之用后抛弃过于古老改动记录?(往往这么做不会引发什么不好的后果,方法是在退出时允许用户选择放弃此次的所有改动。因为当用户对今天所做的操作有过多的不满时,他一般不会撤销数十数百次来恢复最初状态,而是选择放弃一切改动。)
另外一种方法是限制撤销的次数,比如只能撤销最近十次的操作。但如果有过于复杂的改动,很可能只是固定次数的记录可也会占用很大的内存空间。有时这两种方法可以结合使用。比如当撤销记录超过1000条或占用内存超过100M之后自动抛弃最早的改动记录。另外如果这么做,这些数值应该允许用户配置,以满足不同的需要。
另一个要注意的是,有可能一次非常复杂的改动就会占用100M以上的记录空间,是否在这种情况下主动放弃记录这种操作?如果是这样,要提示用户此次操作将不能恢复,要求用户给出肯定的回答。另一种思路就是,无论如何,最近一次的操作必须可以恢复。
还有一种方法,将提供近乎无限的恢复,就是把恢复记录写到硬盘里,这样做的另一个好处是,即使程序退出了下次还是能恢复。不过这种做法并不多见。因为如果真的数据重要,或数据量很大,传统的做法是要求用户自己备份,或者让程序提供备份功能。而不是去提供一个无际的撤销功能。