前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用命令模式实现撤销与恢复 命令模式定义撤销与重做功能就此实现。整个过程中,最关键部分是命令对象的封装以及控制类与具体工厂类耦合的解除。

用命令模式实现撤销与恢复 命令模式定义撤销与重做功能就此实现。整个过程中,最关键部分是命令对象的封装以及控制类与具体工厂类耦合的解除。

作者头像
用户2434869
发布2019-03-29 15:42:15
1.7K0
发布2019-03-29 15:42:15
举报
文章被收录于专栏:yl 成长笔记

命令模式实现撤销与恢复

命令模式定义

将请求封装成对象,以便使用不同的请求、队列或日志来参数化其他对象。 命令对象可以把行动及参数封装起来,于是这些行动可以被:

  • 重复多次
  • 取消
  • 恢复(取消后又再)

整个模式的类图如下:

命令模式
命令模式

通过 ICommand 接口,实现了控制类与调用者的解耦。 * 下面通过一个简单的实例来详细说明这种解耦以恢复撤销是如何实现。 假定有一个风扇,当前有四个按钮,分别是 高速模式 , 低速模式 , 撤销恢复**。

风扇类类如下(对应类图中的具体类 ConcreteClass):

有高速运转、低速运转等方法

代码语言:javascript
复制
public class CeilingFan
{
     public const int HIGH = 2;
     public const int LOW = 1;
     public const int OFF = 0;
     int speed;

     public CeilingFan() { speed = OFF; }
     public void High() { speed = HIGH; }
     public void Low() { speed = LOW; }
     public int getSpeed() { return speed; }
}

命令接口

代码语言:javascript
复制
public interface ICommand
{
    void execute();
    void undo();
}

风扇命令类 (Concrete)

代码语言:javascript
复制
// 高速运行类
public class CeilingFanHighCommand : ICommand
{
    CeilingFan ceilingFan; // 类中不用 new 方法创建类,降低耦合
    int preSpeed;  // 记录执行按键前的状态,便于回测
    public CeilingFanHighCommand(CeilingFan cf)
    {
        ceilingFan = cf;
    }

    public void execute()
    {
        preSpeed = ceilingFan.getSpeed();
        ceilingFan.High(); 
    }

    public void undo()
    {
        switch(preSpeed)
        {
            case CeilingFan.HIGH:
                ceilingFan.High();
                break;
            case CeilingFan.LOW:
                ceilingFan.Low();
                break;
            default:
                ceilingFan.Off();
                break;
        }
    }
}

// 低速运行类
public class CeilingFanLowCommand : ICommand
{
    CeilingFan ceilingFan; // 类中不用 new 方法创建类,降低耦合
    int preSpeed;  // 记录执行按键前的状态,便于回测
    public CeilingFanHighCommand(CeilingFan cf)
    {
        ceilingFan = cf;
    }

    public void execute()
    {
        preSpeed = ceilingFan.getSpeed();
        ceilingFan.Low(); 
    }

    public void undo()
    {
        switch(preSpeed)
        {
            case CeilingFan.HIGH:
                ceilingFan.High();
                break;
            case CeilingFan.LOW:
                ceilingFan.Low();
                break;
            default:
                ceilingFan.Off();
                break;
        }
    }
}

// 关闭类
public class CeilingFanLowCommand : ICommand
{
    CeilingFan ceilingFan; 
    int preSpeed;
    public CeilingFanHighCommand(CeilingFan cf)
    {
        ceilingFan = cf;
    }

    public void execute()
    {
        preSpeed = ceilingFan.getSpeed();
        ceilingFan.Off(); 
    }

    public void undo()
    {
        switch(preSpeed)
        {
            case CeilingFan.HIGH:
                ceilingFan.High();
                break;
            case CeilingFan.LOW:
                ceilingFan.Low();
                break;
            default:
                ceilingFan.Off();
                break;
        }
    }
}

以上风扇的相关命令构建后,需要被一个类来调用控制它,这个控制类不仅仅可以控制风扇,同时可以控制电灯,冰箱等等,所以不能与风扇耦合。

控制类 (对应类图中 Control)

代码语言:javascript
复制
public class Control
{
    List<ICommand> onCommands;
    Stack<ICommand> undoCommands;
    Stack<ICommand> redoCommands;  // 记录前一个命令, 便于 undo

    public Control()
    {
        onCommands = new List<ICommand>();
        undoCommands = new Stack<ICommand>();
        redoCommands = new Stack<ICommand>();
    }

    public void SetCommand(int slot, ICommand onCmd)
    {
        onCommands[slot] = onCmd;
    }

    public void OnButtonWasPressed(int slot)
    {
        if (onCommands[slot] != null)
        {
            onCommands[slot].execute();
            undoCommands.Push(onCommands[slot]);
        }
    }

    public void UndoButtonWasPressed() // 撤销,此处用 stack 后进先出的特性
    {
        if (undoCommands.Count > 0)
        {
            ICommand cmd = undoCommands.Pop();
            redoCommands.Push(cmd);
            cmd.undo();
        }
    }

    public void RedoButtonWasPressed()
    {
        if(redoCommands.Count > 0)
        {
            ICommand cmd = redoCommands.Pop();
            undoCommands.Push(cmd);
            cmd.execute();
        }
    }
}

以上一个命令模式大体上完成了。 下面让客户进行调用测试

代码语言:javascript
复制
// 测试类 (类途中的 RemoteLoader)
class Program
{
    static void Main(string[] args)
    {
        CeilingFan cf = new CeilingFan();
        CeilingFanHighCommand cfh = new CeilingFanHighCommand(cf);
        CeilingFanLowCommand cfl = new CeilingFanLowCommand(cf);

        Control ctr = new Control();
        // 假设 button0, button1 分别为高速低速
        ctr.SetCommand(0, cfh);
        ctr.SetCommand(1, cfl);

        ctr.OnButtonWasPressed(0);
        ctr.OnButtonWasPressed(1);
        ctr.UndoButtonWasPressed();
        ctr.RedoButtonWasPressed();
    }
}

输出内容如下:

turn ceilfan to high speed! turn ceifan to low speed! turn ceilfan to high speed! turn ceifan to low speed!

撤销与重做功能就此实现。整个过程中,最关键部分是命令对象的封装以及控制类与具体工厂类耦合的解除。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 命令模式实现撤销与恢复
    • 命令模式定义
      • 整个模式的类图如下:
      • 风扇类类如下(对应类图中的具体类 ConcreteClass):
      • 命令接口
      • 风扇命令类 (Concrete)
      • 控制类 (对应类图中 Control)
      • 输出内容如下:
    • 撤销与重做功能就此实现。整个过程中,最关键部分是命令对象的封装以及控制类与具体工厂类耦合的解除。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档