美文网首页
编辑器的模式(1)—undo/redo

编辑器的模式(1)—undo/redo

作者: golden_age | 来源:发表于2016-08-20 23:23 被阅读0次

    "我不能预见每个人的未来,我只能预见我自己的,而且只能预见两分钟"——尼古拉斯.凯奇《惊魂下一秒》2007

    无论人写字,画画一样,我们常常有笔误不可避免,
    回到过去的某个修改点,做出不同的修改,并继续,

    在程序设计的概念里,这常常指版本管理,版本管理保存了每一次(所有)修改的历史,不同时间线,还有合并

    图1:版本管理

    而编辑器的,undo/redo, 则有几点简化,

    1. 只保留一部分修改记录——通常我们只关心近期的修改,
    2. undo/redo 为逆操作,但undo不销毁历史,而任何undo之后的修改,则会销毁redo序列
    图2:undo/redo历史线

    这像是《惊魂下一秒》里的故事,修正有限历史,并让下一秒冲刷掉未来。

    undo/redo模式,即为,维护一定长度的修改点队列,并在所有历史修改点里,进行版本切换.

    以下我实现了一个简单的undo/redo,版本管理,

    //版本数据库,为了实现备份,data须可clone  
    public class DataBackup<Data> where Data : class, ICloneable, new()
    {
        //版本队列
        List<Data> mDataBackup = new List<Data>() { new Data() };
        const int MAX_LEN = 15;//版本历史限制
        int dataIdx = 0;//版本号
    
        public Data data
        {
            get
            {
                return mDataBackup[dataIdx];
            }
        }
    
        private void trim()
        {
            mDataBackup.RemoveRange(dataIdx + 1, mDataBackup.Count - dataIdx - 1);
        }
        
        //备份
        public void backup()
        {
            trim();//消除所有未来版本
            mDataBackup.Add(data.Clone() as Data);
            if (dataIdx > MAX_LEN)
            {
                mDataBackup.RemoveAt(0);
            }
            dataIdx = mDataBackup.Count - 1;
        }
    
        //撤销
        public void undo()
        {
            dataIdx--;
            if (dataIdx < 0)
                dataIdx = 0;
        }
    
        //重做
        public void redo()
        {
            dataIdx++;
            if (dataIdx >= mDataBackup.Count)
                dataIdx = mDataBackup.Count - 1;
        }
    }
    
    图三. 撤销/重做测试

    可以看到,这样简单的undo/redo已经足够工作。

    实现更精巧的 redo/undo功能,你需要考虑以下问题:

    • 当data特别大,每一个版本仅需要保存版本增量,因此需要实现,
      gain(data_v1, diff) == data_v2
      revert(data_v2, diff) == data_v1

    • MVC模式下,不一定是对于modeller的数据集, 每次备份能可以是controller 操作集 action list,因此control需要实现 一组可逆接口,例如,
      addEntity/removeEntiy
      changeDeltaPos(x, y) / changeDeltaPos(-x, -y)

    而现实中,对于有些编辑器的实现来说,效率并不是一个严重的问题,简单则是更为重要的。

    相关文章

      网友评论

          本文标题:编辑器的模式(1)—undo/redo

          本文链接:https://www.haomeiwen.com/subject/ejrgjttx.html