雙向同步時撤銷重做設計思路

 其實要說撤銷重做的設計思路,其實沒有啥特別的.這裏主要還是針對雙向同步的情況. 同步時有的人在增,有的人在刪,況且操作因爲網絡的問題還有滯後性,又不能先協調後生效(這樣同步體驗太差), 一想就是一團亂麻.

單機撤銷

 首先來說單機情況的撤銷重做. 通常的思路就是做一個操作鏈:

[START]~_p_[END]  一個當前指針pNow指向[END] 
[START]~[+A]~[+B]~[+C]~[-C]~[-B]~[-A]~_p_[END]  這是做了三次增和三次刪操作的操作鏈pNow也是指向[END]

 此時執行撤銷1次,pNow前移,pNow經過的節點被返回,告訴調用者是”刪除”動作,應該執行”恢復”. 執行後的操作鏈變成這樣:

[START]~[+A]~[+B]~[+C]~[-C]~[-B]~ _p_ [-A]~ [END]. 

 那麼什麼時候會刪除或者說截斷操作鏈呢? 這要看策略,至少有兩種策略.

  • 策略1: 當產生新的操作時,pNow後面的操作記錄全部刪除. 這是絕大多數撤銷重做功能的策略.後面記錄中的有些對象如果沒有必要可以真正的刪除.
  • 策略2: 總是在pNow指針前面插入,pNow之後的操作不刪除. 這種策略也有少數軟件採用.這種策略的效果是所有動作都不會消失.

     +A,+B,撤銷,+C這套動作,在策略1中會留下+A和+C兩個操作,而策略B會留下+A+C+B三個操作.

真正刪除

 一般來說,撤銷都是存在步數限制的,這也可以理解爲操作鏈長度限制. 一次撤銷清掉的對象肯定是不能刪除的,它要隱藏起來,重做的時候可以恢復. 對於策略2一般就不刪任何操作了(否則它的優勢就沒了),只就策略1來講哪些對象是可以真正刪除,哪些又不可以呢?
 對於單純單機的思路,可以做一些合理假設,如增操作後面只能是刪操作,不可能增2次或刪兩次. 一個操作鏈中只可能有某對象的一對增刪操作,因爲正常操作不可能把刪除的對象又add進來(當然這也不是絕對,如果可以add回來就不能這麼假設了),且增操作總是先於刪.
 有以上假設後,哪些對象可以真刪的判斷變的比較容易,但是我要說雙向同步時的情況更復雜,你不能保證你刪的時候,是不是另一個成員也刪了你刪的這個對象,任何假設都只會增加不穩定因素.需要一種更笨更穩妥可靠的辦法.
 笨辦法就是把pNow前面的全部涉及對象都收集起來,然後處理pNow後面要刪的操作,凡是前面存在操作的對象,都不能真刪對象.
 如果採用策略2也就不用考慮要刪誰了,全部保留!

唯心主義同步思路

 一種思路是撤銷重做作爲一個指令,交由裁決者或者叫他主持,主持決定指令影響的對象ID,將指令+ID通知到其他人.這樣的思路其實已經是經過深思熟慮的了.
 “唯心主義”的設計思路.且不說哪種好, 我也沒有能完全理清. 做法是任何一端,不管你是添加,刪除操作,還是撤銷,重做操作,結果就是使得對象增加或者移除了. 我只要把結果通知出去,至於我是何種方式造成的,你不用管.
 那麼在”+A,+B,撤銷,撤銷”的操作序列下,對方得到的同步通告就是+A,+B,-B,-A. 也就是說對方在不操作的情況下,看到A和B出現又消失了. 如果此時對方不斷使用”撤銷”,他將把他剛纔看到的4個(注意是4個不是2個)動作撤銷了一遍,而剛纔的操作方如果還”撤銷”的話,因爲pNow已經移到操作鏈首,不會有任何反應.
 更進一步,對方的四次撤銷,最後結果是AB都不見了. 但是對開始的操作方來說,它的撤銷給我增加了4個操作,分別是+A+B-B-A
 最後的結果是雖然雙方的操作鏈並不相同,但是動作卻神奇的同步了(限於不同時刪除同一個對象的情況).
 這套辦法的優點就是在紛亂複雜的情況下兼顧自己的操作鏈和操作最終同步.

缺陷(TODO)

同時刪除同一對象缺陷
 很顯然,上面的唯心主義同步思路的描述還是沒有解決同時刪除同一對象的問題.如果任其發展的話,操作雙方會得到+A-A-A這樣的操作鏈,如果撤銷兩次難保不會引發給多的問題. 所以這個缺陷需要控制不再重複加入-A操作
真正刪除缺陷
 前面提到,操作鏈根據策略1是會真正刪除一些對象的.有這麼一種情況,甲執行+A,撤銷,+B,乙的操作鏈是+A-A+B. 甲的操作鏈由於真正刪除,變成+B 只有一個+B,且A已經被真正刪除.那麼如果乙撤銷兩次,A在乙上重新出現,而甲卻沒有了對象A. 這個缺陷的處理考慮是否採用策略2,但總是有點虧.

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