美文网首页
命令模式

命令模式

作者: 狐尼克朱迪 | 来源:发表于2016-10-22 10:42 被阅读0次

定义

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

典型使用场景

  • 维护请求历史
  • 实现回调功能
  • 实现撤消功能

例子

借鉴一个游戏:哥布林小妖精是游戏的主人公之一,用户可以给他施展符咒,让它变大变小,也可让它隐身重现。
首先定义大小与隐身相关的常量:

// 可视的常量
public enum Visibility {
  VISIBLE("visible"), INVISIBLE("invisible"), UNDEFINED("");

  private String title;

  Visibility(String title) {
    this.title = title;
  }

  public String toString() {
    return title;
  }
}

// 大小的常量
public enum Size {
  SMALL("small"), NORMAL("normal"), LARGE("large"), UNDEFINED("");
  private String title;

  Size(String title) {
    this.title = title;
  }

  public String toString() {
    return title;
  }
}

目标可以是哥布林,也可以是其他,因此提供一个基类,哥布林是其一个子类:

// 目标的抽象基类
public abstract class Target {
  private Size size;
  private Visibility visibility;

  public Size getSize() {
    return size;
  }
  public void setSize(Size size) {
    this.size = size;
  }

  public Visibility getVisibility() {
    return visibility;
  }

  public void setVisibility(Visibility visibility) {
    this.visibility = visibility;
  }

  public abstract String toString();

  public void printStatus() {
    System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(),
        getVisibility()));
    System.out.println();
  }
}

// 哥布林小妖精是目标实例
public class Goblin extends Target {
  public Goblin() {
    setSize(Size.NORMAL);
    setVisibility(Visibility.VISIBLE);
  }

  public String toString() {
    return "Goblin";
  }
}

定义命令的抽象对象,隐藏和缩小符咒都是继承自这个对象,每个对象都有执行、撤销和重做三个方法:

public abstract class Command {
  public abstract void execute(Target target); // 执行
  public abstract void undo();  // 撤销
  public abstract void redo();  // 重做
  public abstract String toString();
}

// 具体命令:隐藏符咒
public class InvisibilitySpell extends Command {
  private Target target;

  public void execute(Target target) {
    target.setVisibility(Visibility.INVISIBLE);
    this.target = target;
  }

  public void undo() {
    if (target != null) {
      target.setVisibility(Visibility.VISIBLE);
    }
  }

  public void redo() {
    if (target != null) {
      target.setVisibility(Visibility.INVISIBLE);
    }
  }

  public String toString() {
    return "Invisibility spell";
  }
}

// 具体命令:缩小符咒
public class ShrinkSpell extends Command {

  private Size oldSize;
  private Target target;

  public void execute(Target target) {
    oldSize = target.getSize();
    target.setSize(Size.SMALL);
    this.target = target;
  }

  public void undo() {
    if (oldSize != null && target != null) {
      Size temp = target.getSize();
      target.setSize(oldSize);
      oldSize = temp;
    }
  }

  public void redo() {
    undo();
  }

  public String toString() {
    return "Shrink spell";
  }
}

有了目标以及命令对象,创建一个类,维护命令列表:

// 命令的调用者
public class Wizard {

    // 双向队列
  private Deque<Command> undoStack = new LinkedList<>();
  private Deque<Command> redoStack = new LinkedList<>();

  public Wizard() {}

  // 执行符咒
  public void castSpell(Command command, Target target) {
    System.out.println(this + " casts " + command + " at " + target);
    command.execute(target);
    undoStack.offerLast(command);
  }

  // 撤销上次执行的符咒
  public void undoLastSpell() {
    if (!undoStack.isEmpty()) {
      Command previousSpell = undoStack.pollLast();
      redoStack.offerLast(previousSpell);
      System.out.println(this + " undoes " + previousSpell);
      previousSpell.undo();
    }
  }

  // 重新执行上个符咒
  public void redoLastSpell() {
    if (!redoStack.isEmpty()) {
      Command previousSpell = redoStack.pollLast();
      undoStack.offerLast(previousSpell);
      System.out.println(this + " redoes " + previousSpell);
      previousSpell.redo();
    }
  }

  public String toString() {
    return "Wizard";
  }
}

进行测试:

public class App {
  public static void main(String[] args) {
    Wizard wizard = new Wizard();
    Goblin goblin = new Goblin();

    goblin.printStatus();

    wizard.castSpell(new ShrinkSpell(), goblin);
    goblin.printStatus();

    wizard.castSpell(new InvisibilitySpell(), goblin);
    goblin.printStatus();

    wizard.undoLastSpell();
    goblin.printStatus();

    wizard.undoLastSpell();
    goblin.printStatus();

    wizard.redoLastSpell();
    goblin.printStatus();

    wizard.redoLastSpell();
    goblin.printStatus();
  }
}

分析

命令模式可以维护操作历史列表,便于进行撤销、重做等操作。

参考

iluwatar/java-design-patterns

相关文章

  • 12.vim的使用技巧

    命令模式 、命令行模式、编辑模式: INSERT 首次进入文件: 命令模式输入: 表示 命令行模式出现...

  • 五、Linux vim编辑器

    vim编辑器三种模式:命令模式、编辑模式、末行模式 1.命令模式: vim进入文件后就是命令模式 1.1 命令模式...

  • 终端操作文件

    VIM 模式切换从命令模式->编辑模式:i,a,o,I,A,O从编辑模式->命令模式:ESC从命令模式->末行模式...

  • vim 操作 && Mac 配置本地Apache

    一、vim 的基本命令操作 vim 的模式: 编辑模式 ,命令模式 编辑模式: 命令模式:可以通过命令 最重要的命...

  • Vim高效编辑器

    Vim程序员高效编辑器 命令模式,输入模式,底线命令模式 默认进入vim就是命令模式,输入i变为输入模式 命令模式...

  • Command模式

    命令模式(Command) 命令模式属于对象的行为模式。命令模式又称为行动(Action)模式或交易(Tran...

  • 设计模式详解——命令模式

    本篇文章介绍一种设计模式——命令模式。本篇文章内容参考《JAVA与模式》之命令模式。 一、命令模式的概念 命令模式...

  • Vi编辑器

    命令模式 文本输入模式 末行模式。 插入模式 移动光标: 删除命令: 撤销命令: 重复命令 文本行移动: 复制粘贴...

  • JavaScript设计模式七(命令模式)

    JavaScript设计模式七(命令模式) 定义: 命令模式是最简单和优雅的模式之一,命令模式中的命令指的是一个执...

  • Cisco 路由器配置命令大全(二)

    (1)模式转换命令 用户模式----特权模式,使用命令"enable"特权模式----全局配置模式,使用命令"co...

网友评论

      本文标题:命令模式

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