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

文章目录

  • 前言
  • 思路
  • 代码实现
  • uml类图
  • 总结

前言

最近学习设计模式行为型的模式,学到了备忘录模式提到这个模式可以记录一个对象的状态属性值,用于下次复用,于是便想到了我们在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):备忘录类负责存储文档的状态。它可以保存文档的内容、样式、光标位置等信息。
class Memento {private String content;private String style;private int cursorPosition;// 构造函数和访问方法
}
  1. 命令接口(Command):命令接口定义执行和撤销操作的方法。
interface Command {void execute();void undo();
}
  1. 具体命令类(具体的操作):实现命令接口,执行和撤销文档的具体操作。例如,插入文本、修改样式、移动光标等。
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):文档类维护文档的状态,并提供创建备忘录、恢复状态和执行操作的方法。
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):历史记录类负责存储备忘录对象,并管理执行和撤销操作的命令。
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();}}
}

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/90810.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DCL介绍

文章目录 1. 简介2. DCL管理用户3. DCL权限控制 1. 简介 DCL英文全称为&#xff08;数据控制语言&#xff09;&#xff0c;用来管理数据库用户、控制数据库的访问权限 2. DCL管理用户 查询用户 Use mysql; select * from user;创建用户 create user 用户名主机名 Identifi…

【UE 材质】模型部分透明

材质节点如下&#xff0c;这里简单解释一下。首先通过“Mask”节点将"Texture Coordinate" 节点中的“G”通道分离出来&#xff0c;然后通过“if”节点进行判断&#xff0c;当值小于0.5时为透明&#xff0c;当颜色不小于5时为不透明。可以通过一个参数来控制模型透明…

C++实现客户端/服务端通信(一)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 C实现客户端/服务端通信&#xff08;一&#xff09; 网络编程的基本概念1. 客户端/服务器通信模型&#xff1a;2. socket函数&#xff1a;3. 主机字节序和网络字节序&#xf…

k8s 常用命令(四)

12、删除pod中的nginx服务及service [rootmaster ~]# kubectl delete deployment nginx -n kube-public [rootmaster ~]# kubectl delete svc -n kube-public nginx-service 13、查看endpoint的信息 [rootmaster ~]# kubectl get endpoints 14、修改/更新&#xff08;镜像、…

用Cmake build OpenCV后,在VS中查看OpenCV源码的方法(环境VS2022+openCV4.8.0) Part III

用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法(环境VS2022openCV4.8.0) Part III 用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法&#xff08;环境VS2022openCV4.8.0&#xff09; Part I_松下J27的博客-CSDN博客 用Cmake build OpenCV后&…

从零构建深度学习推理框架-11 Resnet

op和layer结构 在runtime_ir.cpp中&#xff0c;我们上一节只构建了input和output&#xff0c;对于中间layer的具体实现一直没有完成&#xff1a; for (const auto& kOperator : this->operators_) {if (kOperator->type "pnnx.Input") {this->input_o…

十五、模板方法模式

一、什么是模板方法模式 模板方法&#xff08;Template Method&#xff09;模式的定义如下&#xff1a;定义一个操作中的算法骨架&#xff0c;而将算法的一些步骤延迟到子类中&#xff0c;使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 模板方法模式包含以…

zookeeper 3.8.1安装和入门使用

1、zookeeper环境搭建&#xff08;Windows单机版&#xff09; 1.1、 前提 必须安装jdk 1.8&#xff0c;配置jdk环境变量&#xff0c;步骤略 1.2、安装zookeeper 地址&#xff1a;https://zookeeper.apache.org/ 1.2.1、选择releases版本 1.2.2、下载安装包并解压 1.2.3、配…

成集云 | 钉钉财务费用单同步至畅捷通 | 解决方案

源系统成集云目标系统 方案介绍 财务管理作为企业管理中重要的组成部分&#xff0c;在企业的发展和成长中扮演着重要角色&#xff0c;成集云以钉钉费用单OA审批与畅捷通TCloud系统为例&#xff0c;与钉钉连接器深度融合&#xff0c;通过数据处理和字段匹配实现了费用…

【redis问题】Caused by: io.netty.channel

遇到的问题&#xff1a; 在使用 RedisTemplate 连接 Redis 进行操作的时候&#xff0c;发生了如下报错&#xff1a; 测试代码为&#xff1a; 配置文件&#xff1a; 问题根源&#xff1a; redis没有添加端口映射解决方案&#xff1a; 删除原来的redis容器&#xff0c;添加新…

高忆管理:大盘是什么意思?

随着市场经济的开展&#xff0c;股票、基金等金融出资产品的普及&#xff0c;大盘这个词汇也逐步进入了咱们的生活中。那么&#xff0c;大盘又是什么意思呢&#xff1f; 从基本概念视点来看&#xff0c;大盘是指股票市场全体走势的指标。出资者经过调查大盘指数的改变&#xf…

luckfox pico 使用记录

连接 使用USB转TTL 连接 USB 也要一起插上 在显示控制台窗口上会显示板子的IP地址 USB接上后 会在网络和共享中心发现 以太网2&#xff08;通过RNDIS 通过USB 将板当网卡用,但使用网络共享&#xff0c;无法ping 通外部网&#xff09; 可以不关闭防火墙&#xff08;WIN10 6…