可撤消的命令设计模式

可撤销命令设计模式是一种行为模式,它扩展了命令模式,允许撤销操作。当您想在应用程序中实现“撤销”或“重做”等功能时,此模式非常有用。下面详细介绍了该模式的工作原理及其实现方式。

关键组件

  1. 命令接口:这定义了命令的契约,通常使用诸如execute()和unexecute()(撤消命令)之类的方法。
  2. 具体命令:接口的具体实现Command,其中每个命令都封装了一个特定的操作以及如何撤消它。它维护撤消自身所需的状态。
  3. Invoker:此对象触发命令的执行。它还可以维护已执行命令的历史堆栈,以便在撤消/重做操作时轻松访问。
  4. 接收者:实际执行工作的对象。命令对象将把工作委托给此接收者。
  5. 历史堆栈:维护的已执行命令堆栈,以允许应用程序回顾先前执行的命令并撤消它们。

Java 中的示例
这是 Java 中可撤消命令模式的一个示例。
步骤 1:定义命令接口

interface Command {
    void execute();
    void unexecute();
}


步骤 2:创建接收器
接收器可以是任何东西,但假设我们有一个TextEditor允许添加或删除文本的接收器。

class TextEditor {
    private StringBuilder text = new StringBuilder();

    public void addText(String newText) {
        text.append(newText);
    }

    public void removeText(int length) {
        text.delete(text.length() - length, text.length());
    }

    public String getText() {
        return text.toString();
    }
}

步骤 3:实施具体命令
让我们创建两个命令:一个用于添加文本,一个用于删除文本。

class AddTextCommand implements Command {
    private TextEditor editor;
    private String text;

    public AddTextCommand(TextEditor editor, String text) {
        this.editor = editor;
        this.text = text;
    }

    @Override
    public void execute() {
        editor.addText(text);
    }

    @Override
    public void unexecute() {
        editor.removeText(text.length());
    }
}


步骤 4:实现调用程序
将Invoker跟踪命令历史并管理撤消操作。

import java.util.Stack;

class CommandInvoker {
    private Stack<Command> commandHistory = new Stack<>();

    public void executeCommand(Command command) {
        command.execute();
        commandHistory.push(command);
    }

    public void undo() {
        if (!commandHistory.isEmpty()) {
            Command command = commandHistory.pop();
            command.unexecute();
        }
    }
}


步骤5:使用模式
以下是我们使用这个Undoable Command模式的方法。

public class Main {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        CommandInvoker invoker = new CommandInvoker();

        Command addHello = new AddTextCommand(editor, "Hello ");
        Command addWorld = new AddTextCommand(editor, "World!");

        invoker.executeCommand(addHello);
        invoker.executeCommand(addWorld);

        System.out.println("After additions: " + editor.getText());

        invoker.undo();
        System.out.println("After undo: " + editor.getText());

        invoker.undo();
        System.out.println("After second undo: " + editor.getText());
    }
}


优点

  • 关注点分离:每个命令都被封装为一个对象,从而可以轻松添加、删除或修改命令,而无需更改其他代码。
  • 撤消/重做支持:该模式本质上提供了一种实现撤消/重做功能的方法。
  • 可扩展性:无需改变现有代码即可添加新命令。
使用案例
  • 文本编辑器(撤消/重做操作)
  • 绘图应用程序(撤消/重做形状和转换)
  • 数据库中的事务管理(回滚)

可撤消命令模式在用户操作需要可逆的应用程序中特别有用,它提供了一种灵活而强大的方式来处理复杂的用户交互序列。