设计模式备忘录+命令模式实现Word撤销恢复操作

文章目录

前言

最近学习设计模式行为型的模式,学到了备忘录模式提到这个模式可以记录一个对象的状态属性值,用于下次复用,于是便想到了我们在Windows系统上使用的撤销操作,于是便想着使用这个模式进行一次模仿复现

思路

以下是按照备忘录和命令模式结合的思路描述:

  1. 首先,我们有一个文档类 Document,其中包含一个文本属性。文档类提供了设置和获取文本的方法。

  2. 我们引入备忘录类 Memento,用于保存文档对象的状态。

  3. 文档类还实现了创建备忘录和恢复备忘录的方法。创建备忘录时,文档对象会将当前的文本状态传递给备忘录对象进行保存。恢复备忘录时,文档对象会从备忘录对象中获取之前保存的文本状态并恢复。

  4. 为了实现可逆操作和撤销功能,我们引入了命令接口 Command,该接口定义了执行方法 execute() 和撤销方法 undo()

  5. 具体命令类 InsertTextCommand 是一个插入文本操作的具体实现。在执行命令时,该命令对象会调用文档对象的插入文本方法,并将执行前的文本状态保存到备忘录对象中。在撤销命令时,该命令对象会使用备忘录对象恢复文档的文本状态。

  6. 历史记录类 History 充当调用者的角色,用于记录执行的命令。它内部使用一个列表来保存命令对象。每次执行命令时,该命令对象被添加到列表中保存;每次撤销命令时,列表的最后一个命令对象被取出并执行其撤销操作。

  7. 在主程序中,我们实例化了文档对象、备忘录对象和历史记录对象。

  8. 执行插入文本命令1,创建插入文本命令对象并将其添加到历史记录对象的列表中。该命令对象会执行插入文本操作,并将执行前的文本状态保存到备忘录对象中。

  9. 执行插入文本命令2,同样创建插入文本命令对象并将其添加到历史记录对象的列表中。该命令对象也会执行插入文本操作,并将执行前的文本状态保存到备忘录对象中。

  10. 执行撤销命令,历史记录对象的列表中取出最后一个命令对象(即插入文本命令2),并执行其撤销操作。命令对象会从备忘录对象中获取之前保存的文本状态,恢复文档的内容。

  11. 输出文档的内容,即输出 "Hello"。

  12. 再次执行撤销命令,历史记录对象的列表中取出插入文本命令1,并执行其撤销操作。文档的内容变为空字符串。

  13. 输出文档的内容,即输出空字符串。

  14. 尝试再次执行撤销命令,由于历史记录中已没有可撤销的命令,不会执行任何操作。

  15. 最后,输出文档的内容,依然输出空字符串。

代码实现

实现类似于 Word 文档中的撤销和恢复操作,可以采用备忘录模式配合命令模式的方式。

  1. 备忘录类(Memento):备忘录类负责存储文档的状态。它可以保存文档的内容、样式、光标位置等信息。
java 复制代码
class Memento {
    private String content;
    private String style;
    private int cursorPosition;

    // 构造函数和访问方法
}
  1. 命令接口(Command):命令接口定义执行和撤销操作的方法。
java 复制代码
interface Command {
    void execute();
    void undo();
}
  1. 具体命令类(具体的操作):实现命令接口,执行和撤销文档的具体操作。例如,插入文本、修改样式、移动光标等。
java 复制代码
class InsertTextCommand implements Command {
    private Document document;
    private Memento prevState;
    private String newText;

    public InsertTextCommand(Document document, String newText) {
        this.document = document;
        this.newText = newText;
    }

    public void execute() {
        prevState = document.createMemento();
        document.setText(newText);
    }

    public void undo() {
        document.restore(prevState);
    }
}
  1. 文档类(Originator):文档类维护文档的状态,并提供创建备忘录、恢复状态和执行操作的方法。
java 复制代码
class Document {
    private String text;

    public void setText(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public Memento createMemento() {
        return new Memento(text);
    }

    public void restore(Memento memento) {
        text = memento.getState();
    }
}
  1. 历史记录类(Caretaker):历史记录类负责存储备忘录对象,并管理执行和撤销操作的命令。
java 复制代码
class History {
    private Stack<Command> commandStack;

    public History() {
        commandStack = new Stack<>();
    }

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

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

使用以上设计的示例代码如下:

java 复制代码
    public static void main(String[] args) {
        // 创建文档对象和历史记录对象
        Document document = new Document();
        History history = new History();

        // 执行命令:插入文本
        Command insertCommand1 = new InsertTextCommand(document, "Hello");
        history.executeCommand(insertCommand1);

        // 执行命令:插入文本
        Command insertCommand2 = new InsertTextCommand(document, " World!");
        history.executeCommand(insertCommand2);
        

        // 输出文档内容
        System.out.println(document.getText());  // 输出:World!

        // 执行命令:撤销上一个命令
        history.undo();

        // 输出文档内容
        System.out.println(document.getText());  // 输出:hello

        // 执行命令:撤销上一个命令(没有可撤销的命令)
        history.undo();  // 不执行任何操作

        // 输出文档内容
        System.out.println(document.getText());  // 输出:""
    }

通过使用备忘录模式和命令模式,我们可以记录文档状态的变化,并在需要时进行撤销和恢复操作。每次执行操作时,都会创建对应的命令对象,并将其添加到历史记录中,以支持撤销和重做操作。

uml类图

总结

这个功能的实现使用了备忘录模式和命令模式两种设计模式。

备忘录模式用于保存文档对象的状态,并提供了恢复状态的功能。它将文档对象的状态封装在备忘录对象中,以便在需要时可以对其进行保存并恢复。这样,可以在不破坏文档对象封装性的情况下,实现文档对象的状态管理和回滚功能。

命令模式用于执行和撤销操作。通过将每个操作封装在一个命令对象中,并提供统一的执行和撤销方法,可以实现对操作的统一管理和控制。这样,可以方便地扩展和组合不同的操作,同时也解耦了调用者和接收者。

使用设计模式的好处包括:

  1. 提高代码的可维护性和可扩展性:设计模式使代码结构更清晰、更易于理解和维护。模式中定义了明确的角色和关系,使代码具有良好的组织结构和可扩展性。

  2. 复用性增加:设计模式通过提供通用的解决方案,使得代码可以在不同场景下被重复使用。这避免了重复编写相似的代码,提高了开发效率。

  3. 降低耦合度:设计模式通过明确角色和关系,将系统中各组件之间的依赖关系降到最低。这样,当需求变化或者需要修改某一个组件时,对其他组件的影响最小,易于维护和扩展。

  4. 提高代码的可测试性:设计模式将逻辑分离开来,使得每个模块可以独立地进行测试,便于编写单元测试和集成测试。

相关推荐
小白不太白9501 小时前
设计模式之 责任链模式
python·设计模式·责任链模式
吾与谁归in2 小时前
【C#设计模式(13)——代理模式(Proxy Pattern)】
设计模式·c#·代理模式
吾与谁归in2 小时前
【C#设计模式(14)——责任链模式( Chain-of-responsibility Pattern)】
设计模式·c#·责任链模式
闲人一枚(学习中)2 小时前
设计模式-创建型-原型模式
设计模式
Iced_Sheep2 小时前
干掉 if else 之策略模式
后端·设计模式
哪 吒10 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_102210 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
转世成为计算机大神13 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
小乖兽技术14 小时前
23种设计模式速记法
设计模式
小白不太白95015 小时前
设计模式之 外观模式
microsoft·设计模式·外观模式