三種undo/Redo的實現

一、基於對象序列化的Undo\Redo

Rockford LhotkaCSLA框架中,介紹了一種基於保存序列化對象入棧的Undo\Redo實現方案。調用BeginEdit函數時,通過反射機制將整個業務對象的所有Field序列化,並保存在UndoStack中。在Undo時,將保存在UndoStack中的序列化的Map值讀出來,對現有的業務對象進行數值還原。

由於使用對象序列化的方式來保存對象的歷史。所以當UndoStack比較深,或是業務對象比較大的時候會佔用比較多的內存,性能上也不盡如人意。但是CSLAUndo實現方式通用性較好。所以適用範圍還是不小的。

二、基於Command模式的Undo\Redo

GoF的名著《Design Patterns》中介紹了著名的Command的模式,主要用途之一就是用來實現Undo\Redo的。具體實現方式就不在這裏介紹了,有興趣可以參考《Design Patterns》一書。

靈活運用這種實現方式可以應對各種Undo操作,但是是以損失一定的可複用性爲代價的。一個可以Undo的操作越具體,它和實現應用的關係就越緊,抽象性就越差,也就越難以複用。其極端情況就是每個Command都要符合ACID

最重要的是,如果要使用Command模式來實現Undo機制,最好是在開始寫代碼之前就做這個決定,並自始至終使用Command來響應用戶請求。如果等到所以的代碼都寫到Click事件處理函數裏的時候,再想用Command來實現Undo\Redo就麻煩了。

三、結合RoutedEventObserver模式和Command模式的Undo\Redo

爲了解決上面兩種Undo實現方式的缺點,既保證通用性,又能減少資源佔用。可以將上面的兩種方式結合起來,並聯合和RoutedEvent機制和Observer模式。

RoutedEvent.NET 3.0中的WPF裏的新型的事件傳遞機制。主要特點是子對象的事件發生後會觸發父對象的相應事件。從而簡化事件的訂閱。但是WPF裏的RoutedEvent只能用在UIElement上,業務對象就無福消受了。所以可以自己實現一個簡單的RoutedEvent機制來簡化事件的訂閱。

然後用一個Watcher對象監視業務對象的變化,將變化抽象、封裝成一個可以UndoRedoCommand。大致可以分成PropertyChangedEditionItemChangedEdition兩種,就可以提供對於屬性改變、從List中刪除、向List添加、ListItem Move這些常見操作的UndoRedo

當然這種方式也有不好的地方,由於抽象程度比較高,所以這種Undo機制並不能很好地和業務邏輯契合,比如List AList B的添加、刪除是同步且應該被視爲一個操作時,這種機制還是認爲是兩個操作。

 

    上面介紹了兩種常見的UndoRedo的方式和一種新的實現方式,算是拋磚引玉,幫助大家找到更適合自己的Undo Redo實現方式。

例子http://www.cnblogs.com/vivid-stanley/archive/2007/02/13/649824.html

Qt Undo Frameworkhttp://www.cppblog.com/eryar/archive/2015/01/13/209504.html  QUndoCommand

發佈了82 篇原創文章 · 獲贊 138 · 訪問量 79萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章