撤销与反撤销 功能实现

简介: 你一定经常看见类似下面的图标:        它们就表示“撤销”与“反撤销”。在程序中,这种功能通常是使用Command模式实现的,本文也不例外。首先抽象定义Command,使用ICommand接口:     public interface ICommand    {        void Excute() ;    }     Excute表示执行该ICommand引用的目标的所包含的动作(或动作序列)。

    你一定经常看见类似下面的图标:
   
    它们就表示“撤销”与“反撤销”。在程序中,这种功能通常是使用Command模式实现的,本文也不例外。首先抽象定义Command,使用ICommand接口:

    public   interface  ICommand
    {
        
void  Excute() ;
    }

    Excute表示执行该ICommand引用的目标的所包含的动作(或动作序列)。
    
    可撤销的命令也是一种命令,所以从ICommand继承:
   

    public   interface  IBackableCommand :ICommand
    {
        
void  Undo() ;
    }

    一个可撤销的命令表明调用其Excute方法后,再调用其Undo方法可以使被操作的对象回复到之前的状态。

    为了实现撤销功能,我们需要一个堆栈来记录所有已执行的可撤销命令,为了实现反撤销的功能,同样,我们也需要一个堆栈来记录所有已撤销的命令。这个职责是由ICommandManager接口提供:
   

    public   interface  ICommandManager
    {
        
void  ExcuteCommand(ICommand command) ;
        
void  Undo() ;
        
void  ReverseUndo() ; // 反撤销

        
// 以下事件可用于控制撤销与反撤销图标的启用
         event  CbSimpleBool UndoStateChanged ;  // bool参数表明当前是否有可撤销的操作
         event  CbSimpleBool ReverseUndoStateChanged ;  // bool参数表明当前是否有可反撤销的操作
    }


    现在,我们来详细分析一下,撤销命令堆栈和反撤销命令堆栈在何时Push命令对象、又在何时Pop命令对象:
(1)当执行完任何一个command后,reverseUndo堆栈清空
(2)当执行完一个不可撤销的command后,undo堆栈清空
(3)当执行完一个可撤销的command后,将其压入undo堆栈
(4)当撤销一个command后,将其转移到reverseUndo堆栈

    基于此,我们就可以实现ICommandManager:

    public   class  CommandManager :ICommandManager
    {
        
private  Stack undoStack     =   new  Stack() ;
        
private  Stack reverseStack  =   new  Stack() ;

        
public   event  CbSimpleBool UndoStateChanged ; 
        
public   event  CbSimpleBool ReverseUndoStateChanged ; 

        
public  CommandManager()
        {
            
this .UndoStateChanged          +=   new  CbSimpleBool(CommandManager_UndoStateChanged);
            
this .ReverseUndoStateChanged  +=   new  CbSimpleBool(CommandManager_UndoStateChanged) ;
        }

        
private   void  CommandManager_UndoStateChanged( bool  val)
        {

        }

        
#region  ICommandManager 成员

        
public   void  ExcuteCommand(ICommand command)
        {
            command.Excute() ;
            
this .reverseStack.Clear() ;

            
if (command  is  IBackableCommand)
            {
                
this .undoStack.Push(command) ;
            }
            
else
            {
                
this .undoStack.Clear() ;
            }

            
this .UndoStateChanged( this .undoStack.Count  >   0 ) ;
        }

        
public   void  Undo()
        {
            IBackableCommand command 
=  (IBackableCommand) this .undoStack.Pop() ;
            
if (command  ==   null )
            {
                
return  ;
            }

            command.Undo() ;
            
this .reverseStack.Push(command) ;

            
this .ReverseUndoStateChanged( this .reverseStack.Count  >   0 ) ;
        }

        
public   void  ReverseUndo()
        {
            IBackableCommand command 
=  (IBackableCommand) this .reverseStack.Pop() ;
            
if (command  ==   null )
            {
                
return  ;
            }

            command.Excute() ;
            
this .undoStack.Push(command) ;

            
this .UndoStateChanged( this .undoStack.Count  >   0 ) ;
            
this .ReverseUndoStateChanged( this .reverseStack.Count  >   0 ) ;
        }
        
#endregion         
    }


    本文介绍的撤销与反撤销功能是与应用无关的,所以可以在不同的应用中复用,你只需要根据你自己的应用需求来实现对应的ICommand接口和IBackableCommand接口就可以立即使用撤销与反撤销功能了。




目录
相关文章
|
6月前
|
存储 设计模式 uml
C++备忘录模式实践:轻松实现撤销与恢复功能
C++备忘录模式实践:轻松实现撤销与恢复功能
105 0
|
存储 设计模式
备忘录模式-实现撤销功能
备忘录模式-实现撤销功能
76 1
|
开发工具 git
git命令回滚撤销自己的错误覆盖提交
git命令回滚撤销自己的错误覆盖提交
116 0
|
缓存 Shell 开发工具
研发中学习git(删除分支/合并提交/回滚/保存当前状态/撤销修改)
研发中学习git(删除分支/合并提交/回滚/保存当前状态/撤销修改)
154 0
|
API 数据库
Revit二次开发—撤销已提交的事务
Revit二次开发—撤销已提交的事务
Revit二次开发—撤销已提交的事务
|
缓存 开发工具 git
git 各种状态下撤销修改的方法
git 各种状态下撤销修改的方法
|
Windows
撤销与取消撤销快捷键
通常有时候需要撤销操作,或者撤销点快了要取消撤销。 记录下如何操作。
904 0
|
开发工具 git
Git版本控制系统回退操作(五)
Git版本控制系统回退操作 1.工作区回退 1)在file1文件中随便写点内容
237 0
Git版本控制系统回退操作(五)
|
索引
Swing 的 undo 包实现撤销/重做功能(上)
Swing 的 undo 包实现撤销/重做功能(上)
203 0
Swing 的 undo 包实现撤销/重做功能(上)