zoukankan      html  css  js  c++  java
  • 文本编辑器中,如何设计 撤销/重复栈

              文本编辑器中,如何设计 撤销/重复栈

                                                      电子科技大学软件学院03级02班 周银辉

            在文本编辑中经常使用到“撤销”操作(Ctrl-Z),以及一个与之相应的“重复”操作(Ctrl-Y),各种不同的编辑操作都可以使用这两个操作来撤销或重复,那么如此多的编辑操作是如何被设计到一起而使得一个“撤销”按钮可以撤销各种不同的操作呢?

    关键在于两点:栈 和 多态。

    如何设计:
           很容易想到使用栈来保持那些已经被执行的操作,当要撤销上一步操作时,只需要取出栈顶元素并执行该元素所对应的操作便可。
         接踵而至的一个问题是: 栈中元素类型是什么? 由于我们需要保存各种不同的文本编辑操作,要将它们统一地保存在一起,很自然地,我们应该让这些操作有着统一的父类, 我们栈中元素的类型是该父类类型就可以了.
         我们这里设计了一个接口,所有的可撤销/重复的操作都应该继承该接口:

        
    /// <summary>
        
    /// 可撤销重复操作接口。
        
    /// 所有的可重复可撤销的操作都应该继承这个接口。
        
    /// </summary>
        interface IUndoableOperate
        {
            
    void Undo();
            
    void Redo();
            
    void Execute();
        }

           比如我们有一个操作Operate1,它继承了IUndoableOperate接口

        
    /// <summary>
        
    /// 操作1
        
    /// </summary>
        class Operate1 : IUndoableOperate
        {
            
    #region IUndoableOperate 成员

            
    /// <summary>
            
    /// 撤销该操作时执行
            
    /// </summary>
            public void Undo()
            {
                Console.WriteLine(
    "undo operate1");
            }

            
    /// <summary>
            
    /// 重复该操作时执行
            
    /// </summary>
            public void Redo()
            {
                Console.WriteLine(
    "do operate1");
            }

            
    /// <summary>
            
    /// 执行操作1
            
    /// </summary>
            public void Execute()
            {
                
    this.Redo();
            }

            
    #endregion

        }

           其它任何与Operate1类似的操作都可以放到撤销栈中,以便以后撤销。

           栈中元素都是IUndoableOperate类型,那么当我们取出栈顶元素并调用其Execute()函数时,其能被正确的执行吗?答案是肯定的,这利用了多态。

           现在我们可以设计一个管理器来对栈进行管理,它将记录那些被执行或被撤销的操作,并提供方法允许你对已经执行过的操作进行撤销、已经撤销的操作进行重复。

        
    /// <summary>
        
    /// 撤销重复操作管理器
        
    /// </summary>

        class UndoStackManager
        
    {
            
    /// <summary>
            
    /// 撤销栈
            
    /// </summary>

            Stack<IUndoableOperate> un_stack = new Stack<IUndoableOperate>();
            
    /// <summary>
            
    /// 重复栈
            
    /// </summary>

            Stack<IUndoableOperate> re_stack = new Stack<IUndoableOperate>();


            
    public void ClearStack()
            
    {
                
    this.un_stack.Clear();
                
    this.re_stack.Clear();
            }


            
    /// <summary>
            
    /// 获取一个值,指示是否有可撤销的操作
            
    /// </summary>

            public bool CanUndo
            
    {
                
    get
                
    {
                    
    return un_stack.Count != 0;
                }

            }


            
    /// <summary>
            
    /// 获取一个值,指示是否有可重复的操作
            
    /// </summary>

            public bool CanRedo
            
    {
                
    get
                
    {
                    
    return re_stack.Count != 0;
                }

            }


            
    /// <summary>
            
    /// 撤销上一操作
            
    /// </summary>

            public void Undo()
            
    {
                
    if (this.CanUndo)
                
    {
                    IUndoableOperate op 
    = un_stack.Pop();
                    op.Undo();
                    re_stack.Push(op);
                }

            }


            
    /// <summary>
            
    /// 重复被撤销的操作
            
    /// </summary>

            public void Redo()
            
    {
                
    if (this.CanRedo)
                
    {
                    IUndoableOperate op 
    = re_stack.Pop();
                    op.Redo();
                    un_stack.Push(op);
                }

            }



            
    /// <summary>
            
    /// 将某一操作存放到撤销栈中
            
    /// </summary>
            
    /// <param name="op"></param>

            public void PushToUndoStack(IUndoableOperate op)
            
    {
                
    this.un_stack.Push(op);
                
    this.re_stack.Clear();
            }

        }

         以下是完整的示例代码:
    完整的示例代码

    示例代码的执行结果是:
    do operate1
    do operate2
    undo operate2
    undo operate1
    do operate1
    do operate2
  • 相关阅读:
    iOS商品详情、ffmpeg播放器、指示器集锦、自定义圆弧菜单、实用工具等源码
    android愤怒小鸟游戏、自定义View、掌上餐厅App、OpenGL自定义气泡、抖音电影滤镜效果等源码
    iOS渐变视图&动画库、腰杆、音频水滴水波手势、多种对话框、四级展开效果等源码
    android应用市场、社区客户端、漫画App、TensorFlow Demo、歌词显示、动画效果等源码
    iOS炫酷动画图案、多种选择器、网络测速、滑动卡片效果等源码
    android多框架实现短视频应用、3D手势旋转、banner控件、指南针、智能管家等应用源码
    iOS 仿看了吗应用、指南针测网速等常用工具、自定义弹出视图框架、图片裁剪、内容扩展等源码
    android完整资讯App、Kotlin新闻应用MVP + RxJava + Retrofit + Dagger2、优雅区间选择器等源码
    iOS运营级B2B服务平台App、自定义图标库、个人中心页面、识别身份证Demo、瀑布流等源码
    Flutter中的浮动按钮 FloatingActionButton
  • 原文地址:https://www.cnblogs.com/zhouyinhui/p/520813.html
Copyright © 2011-2022 走看看