20、设计模式之备忘录模式

server/2024/11/15 0:35:45/

备忘录模式

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。

介绍

意图: 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

主要解决: 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。

何时使用: 很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。

如何解决: 通过一个备忘录类专门存储对象状态。

关键代码: 客户不与备忘录类耦合,与备忘录管理类耦合。

应用实例:

  1. 打游戏时的存档。
  2. Windows 里的 ctrl + z。
  3. 浏览器中的后退。
  4. 数据库的事务管理。

优点:

  1. 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
  2. 实现了信息的封装,使得用户不需要关心状态的保存细节。

缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存。

使用场景:

  1. 需要保存/恢复数据的相关状态场景。
  2. 提供一个可回滚的操作。

注意事项:

  1. 为了符合迪米特原则,还要增加一个管理备忘录的类。
  2. 为了节约内存,可使用原型模式+备忘录模式

代码实现

定义源发器(Originator),notePad

/*** 源发器(Originator)*/
public class NotePad {private final StringBuilder content;private final Stack<Integer> operationStack;public NotePad(){content  = new StringBuilder();this.operationStack = new Stack<>();}public NotePad(String content){this();this.content.append(content);}public void write(String content){operationStack.push(this.content.length());this.content.append(content);}public void undo(){if(operationStack.isEmpty()){System.out.println("undo empty!");return;}int operation = operationStack.pop();int len = this.content.length();this.content.delete(operation,len);}public void toSnap(NotePadSnapshot notePadSnapshot){operationStack.clear();this.content.delete(0,this.content.length());this.content.append(notePadSnapshot.getSnapshot());}public NotePadSnapshot createMemento(){return new NotePadSnapshot(this.content.toString());}public void show(){System.out.println("notePad:"+this.content);}}

定义备忘录类(快照类)

public class NotePadSnapshot {private final String snapshot;public NotePadSnapshot(String snapshot){this.snapshot = snapshot;}public String getSnapshot(){return snapshot;}public void show(){System.out.println("snapshot:"+snapshot);}
}

定义快照的管理类


public class SnapshotManager {private final Map<Integer,NotePadSnapshot> snapshots = new HashMap<>();private final AtomicInteger version = new AtomicInteger(0);public void add(NotePadSnapshot notePadSnapshot){snapshots.put(version.getAndIncrement(),notePadSnapshot);}public NotePadSnapshot get(int version){return snapshots.get(version);}
}

客户端

public class Client {public static void main(String[] args) {NotePad notePad = new NotePad();notePad.write("hello world");notePad.show();notePad.write("i am a boy");notePad.show();notePad.undo();notePad.show();notePad.write("i am a girl");notePad.show();NotePadSnapshot notePadSnapshot = notePad.createMemento();notePadSnapshot.show();SnapshotManager snapshotManager = new SnapshotManager();snapshotManager.add(notePadSnapshot);notePad.write("i am a man");notePad.show();notePad.toSnap(snapshotManager.get(0));notePad.show();}
}

http://www.ppmy.cn/server/44929.html

相关文章

【最优化方法】实验四 约束最优化方法的MATLAB实现

实验的目的和要求&#xff1a;通过本次实验使学生较为熟练使用MATLAB软件&#xff0c;并能利用该软件进行约束最优化方法的计算。 实验内容&#xff1a; &#xff11;、罚函数法的MATLAB实现 &#xff12;、可行方向法的MATLAB实现 学习建议&#xff1a; 本次实验就是要通…

数据库中的六大锁

目录 一、死锁 二、锁的区间划分 1、间隙锁&#xff08;Gap Locks&#xff09; 2、临键锁&#xff08;Next-key Locks&#xff09; 三、锁的粒度划分 1、表级锁&#xff08;Table-level lock&#xff09; 2、行级锁&#xff08;Record Locks&#xff09; 3、页级锁 四、…

5.23.9 TransUNet:Transformers 为医学图像分割提供强大的编码器

TransUNet&#xff0c;它兼具 Transformers 和 U-Net 的优点&#xff0c;作为医学图像分割的强大替代方案。一方面&#xff0c;Transformer 对来自卷积神经网络 (CNN) 特征图的标记化图像块进行编码&#xff0c;作为用于提取全局上下文的输入序列。另一方面&#xff0c;解码器对…

《TCP/IP网络编程》(第十一章)进程间通信

进程间通信意味着两个不同的进程间可以交换数据&#xff0c;它使得不同的进程能够协同工作&#xff0c;实现复杂的系统功能。 1.通过管道实现进程间通信 下图是基于 管道&#xff08;PIPE&#xff09; 的进程间通信结构模型 管道不属于进程的资源&#xff0c;属于操作系统的资…

数据分析项目有哪些实施流程?揭示从数据准备到解决方案全过程

在当今数据驱动的商业环境中&#xff0c;数据分析项目的成功实施对于企业洞察市场趋势、优化产品服务、提升用户体验以及增强竞争力具有至关重要的作用。特别是对于直播类应用软件这样的快速增长领域&#xff0c;如何通过数据分析来扩大付费用户基础、提高用户留存率&#xff0…

Sketch v100 for Mac 安装教程【支持M芯片】

Sketch v100 for Mac 安装教程【支持M芯片】 原文地址&#xff1a;https://blog.csdn.net/weixin_48311847/article/details/139104315

Vue3在Element UI 表格中自定义时间格式化显示

Vue3在Element UI 表格中自定义时间格式化显示 一、前言1、准备工作2、实现步骤1. 引入 Element UI 组件2. 自定义时间格式化函数3. 格式化日期逻辑 3、完整示例4、结论 一、前言 在开发 Web 应用程序时&#xff0c;常常需要在表格中展示时间数据。Element UI 是一个流行的 Vu…

学习thinkphp的循环标签

1.FOREACH标签 foreach标签的用法和PHP语法非常接近&#xff0c;用于循环输出数组或者对象的属性&#xff0c;用法如下&#xff1a; $list User::all(); View::assign(list,$list); 模板文件中可以这样输出 {foreach $list as $key>$vo } {$vo.id}:{$vo.name} {/foreac…