当前位置: 首页 > news >正文

设计模式系列 - 备忘录模式

介绍&定义

备忘录模式,也叫快照(Snapshot)模式,英文翻译是 Memento Design Pattern。在 GoF 的《设计模式》一书中,备忘录模式是这么定义的:

Captures and externalizes an object’s internal state so that it can be restored later, all without violating encapsulation.

翻译成中文就是:在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。

这个模式的定义主要表达了两部分内容。

  1. 一部分是,存储副本以便后期恢复。这一部分很好理解。
  2. 另一部分是,要在不违背封装原则的前提下,进行对象的备份和恢复。这部分不太好理解。

结构

**Originator(原发器):**它是一个需要保存状态的类,可以创建一个备忘录/备份,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态。

**Memento(备忘录):**存储原发器的内部状态。除了原发器类,备忘录类不能被其他类创建和修改。一般通过将Memento类与Originator类定义在同一个包中来实现封装(也可以作为内部类),使用默认访问标识符来定义Memento类,即保证其包内可见。

**Caretaker(负责人):**负责人又称为管理者,它负责保存备忘录。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象(负责任类只提供备忘录对象的读写接口,不提供备忘录属性的读写接口),也无须知道对象的实现细节。负责人对象可以保存一个备忘录数组,从而实现原发器的多次撤销。

实际案例

实现一个 文本编辑器

:ls 查看文本内容

:undo 回退一步

package com.beauty.designpatterns.behavior;import java.util.Scanner;
import java.util.Stack;/*** description 备忘录模式** @author yufengwen* @date 2023/2/20 19:18*/
public class MemoPattern {public static void main(String[] args) {Text text = new Text();BackupHolder snapshotsHolder = new BackupHolder();Scanner scanner = new Scanner(System.in);while (scanner.hasNext()) {String input = scanner.next();if (input.equals(":ls")) {System.out.println(text.toString());} else if (input.equals(":undo")) {Backup backup = snapshotsHolder.popBackup();text.undo(backup);} else {snapshotsHolder.pushBackup(text.backup());text.append(input);}}}
}class Text {private final StringBuilder text = new StringBuilder();public String getText() {return text.toString();}public void append(String input) {text.append(input).append("|");}public Backup backup() {return new Backup(text.toString());}public void undo(Backup backup) {this.text.replace(0, this.text.length(), backup.getText());}@Overridepublic String toString() {return text.toString();}
}class Backup {private final String text;public Backup(String text) {this.text = text;}public String getText() {return this.text;}}class BackupHolder {private final Stack<Backup> backups = new Stack<>();public Backup popBackup() {return backups.pop();}public void pushBackup(Backup backup) {backups.push(backup);}}
jfaj
slkfja
:ls
jfaj|slkfja|
:undo
ls
sif
:ls
jfaj|ls|sif|
:undo
:ls
jfaj|ls|

如何优化内存和时间消耗?

前面我们只是简单介绍了备忘录模式的原理和经典实现,现在我们再继续深挖一下。如果要备份的对象数据比较大,备份频率又比较高,那快照占用的内存会比较大,备份和恢复的耗时会比较长。这个问题该如何解决呢?

不同的应用场景下有不同的解决方法。比如,我们前面举的那个例子,应用场景是利用备忘录来实现撤销操作,而且仅仅支持顺序撤销,也就是说,每次操作只能撤销上一次的输入,不能跳过上次输入撤销之前的输入。在具有这样特点的应用场景下,为了节省内存,我们不需要在快照中存储完整的文本,只需要记录少许信息,比如在获取快照当下的文本长度,用这个值结合对象存储的文本来做撤销操作。

我们再举一个例子。假设每当有数据改动,我们都需要生成一个备份,以备之后恢复。如果需要备份的数据很大,这样高频率的备份,不管是对存储(内存或者硬盘)的消耗,还是对时间的消耗,都可能是无法接受的。想要解决这个问题,我们一般会采用“低频率全量备份”和“高频率增量备份”相结合的方法。

全量备份就不用讲了,它跟我们上面的例子类似,就是把所有的数据“拍个快照”保存下来。所谓“增量备份”,指的是记录每次操作或数据变动。

当我们需要恢复到某一时间点的备份的时候,如果这一时间点有做全量备份,我们直接拿来恢复就可以了。如果这一时间点没有对应的全量备份,我们就先找到最近的一次全量备份,然后用它来恢复,之后执行此次全量备份跟这一时间点之间的所有增量备份,也就是对应的操作或者数据变动。这样就能减少全量备份的数量和频率,减少对时间、内存的消耗。

相关文章:

设计模式系列 - 备忘录模式

介绍&定义 备忘录模式&#xff0c;也叫快照&#xff08;Snapshot&#xff09;模式&#xff0c;英文翻译是 Memento Design Pattern。在 GoF 的《设计模式》一书中&#xff0c;备忘录模式是这么定义的&#xff1a; Captures and externalizes an object’s internal state…...

详细介绍React生命周期和diffing算法

事件处理 1.通过onXxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性&#xff1b;React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ——为了的高效。 2.通过event.target得到发生事件的DOM…...

面向对象的特点

1、什么是对象对象的含义是指具体的某一个事物&#xff0c;即在现实生活中能够看得见摸得着的事物。在面向对象程序设计中&#xff0c;对象所指的是计算机系统中的某一个成分。在面向对象程序设计中&#xff0c;对象包含两个含义&#xff0c;其中一个是数据&#xff0c;另外一个…...

智慧校园平台源码 智慧教务 智慧电子班牌系统

系统介绍 智慧校园系统是通过信息化手段,实现对校园内各类资源的有效集成 整合和优化&#xff0c;实现资源的有效配置和充分利用&#xff0c;将校务管理过程的优化协调。为校园提供数字化教学、数字化学习、数字化科研和数字化管理。 致力于为家长和教师提供一个全方位、多层…...

Vue篇.03-组合式API [setup()]

单文件组件(1)<script setup><script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐启用该语法&#xff0c;需要在 <script> 代码块上添加 setup attribute, 里面的代码会被编译成组件 s…...

QHashIterator-官翻

QHashIterator Class template <typename Key, typename T> class QHashIterator QHashIterator 类为 QHash 和 QMultiHash 提供 Java 风格的常量迭代器。更多内容… 头文件:#include qmake:QT core 所有成员列表&#xff0c;包括继承的成员废弃的成员 公共成员函数…...

[qiankun]-部署后线上问题

[qiankun]-部署后线上问题微服务加载问题-现象1现象描述问题分析解决方案微服务加载问题-现象2现象描述问题分析微服务加载问题-现象3现象描述分析解决方案属于项目打包后&#xff0c;部署到服务器上&#xff0c;所遇到的部分问题 微服务加载问题-现象1 现象描述 项目部署实…...

位图数组 布隆过滤器

文章目录位图数组获取索引获取索引状态设置索引状态布隆过滤器特点大致原理位图数组 一个int类型的整数用4字节,也就是32个bit位来表示&#xff0c;将整数类型的数组转换成位图数组&#xff0c;那么存储长度将变为原来的32倍 arr[0] 表示0-31 arr[1] 表示32-63 //...获取索引…...

多线程Thread常用方法和状态

Thread类 及常见方法 1、常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象&#xff0c;并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象&#xff0c;并命名Thre…...

Codeforces Round #836 (Div. 2)

A SSeeeeiinngg DDoouubbllee 题意&#xff1a;告诉你一个字符串。若该串上每一位上的字母都可以出现两次&#xff0c;求回文串 思路&#xff1a;正向再反向输出s即可 #include <bits/stdc.h> #define lowbit(x) x&(-x) #define ios cin.sync_with_stdio(false)…...

Python学习之项目实践: 写一个MP3播放器

下面呢&#xff0c;是一个 Python MP3 播放器&#xff0c;它使用 pygame 模块来实现音乐播放功能&#xff1a; import pygame class MP3Player: """ MP3 播放器类 """ def __init__(self): pygame.mixer.init() def play(self, file_path): &quo…...

RocketMQTemplate 实现消息发送

代码托管于gitee&#xff1a;easy-rocketmq 文章目录一、前置工作二、消费者三、生产者1. 普通消息2. 过滤消息3. 同步消息4. 延时消息5. 批量消息6. 异步消息7. 单向消息8. 顺序消息9. 事务消息概要Demo源码解读一、前置工作 1、导入依赖 <dependency><groupId>…...

教师干货丨这5款微课必备提效神器,我要告诉全世界!

微课是一种短小精悍的视频教学形式&#xff0c;其设计和演示因特别简洁明了而被定义为“小而美”。由于只在几分钟时间内向学生传授所需知识&#xff0c;微课为学习者提供更多的选择机会和时间节约的便利&#xff0c;而这种趋势已经逐渐在新的社交媒体环境中显现出来。在制作微…...

timm使用swin-transformer

1.安装 pip install timm2.timm中有多少个预训练模型 #timm中有多少个预训练模型 model_pretrain_list timm.list_models(pretrainedTrue) print(len(model_pretrain_list), model_pretrain_list[:3])3加载swin模型一般准会出错 model_ft timm.create_model(swin_base_pat…...

【java基础】java八大基本数据类型和运算符

文章目录说明八大基本数据类型整型浮点型字符型布尔类型类型转换java运算符基础运算符二元运算符自增自减运算符关系和boolean运算符三元运算符位运算符运算符优先级说明 这里介绍java的八大基本数据类型和运算符 八大基本数据类型 java中有八大数据类型&#xff0c;4个整型…...

Mybatis源码学习笔记(四)之Mybatis执行增删改查方法的流程解析

1 Mybatis流程解析概述 Mybatis框架在执行增伤改的流程基本相同&#xff0c; 很简单&#xff0c;这个大家只要自己写个测试demo跟一下源码,基本就能明白是怎么回事&#xff0c;查询操作略有不同&#xff0c; 这里主要通过查询操作来解析一下整个框架的流程设计实现。 2 Mybat…...

浅谈测试用例设计

前言 最近干的最多的事情就是设计测试用例、评审测试用例了&#xff0c;于是我不禁又想到了一个经典的问题&#xff1a;如何设计出优秀的测试用例&#xff1f; 可能有些童鞋看到这个问题会有些不以为然&#xff0c;这有什么好想的&#xff1f;干个测试谁还不会设计测试用例&a…...

python 利用装饰器实现类似于flask路由

例子1&#xff1a; def f1():print(1111)def f2():print(2222)if __name__ __main__:print(33)打印结果&#xff1a; 33 在例子1中&#xff0c;f1() 与f2() 都没有被调用&#xff0c;只执行了print(33) f1与f2&#xff0c;是没有被调用的&#xff0c;但是如果f1 和 f2 上面…...

git 拉取远程分支到本地

目录&#xff1a;***&#xff01;本小作者&#xff0c;是将终端和Git的可视化插件结合使用&#xff0c;刚接触的可以自习看一下&#xff0c;内容简单&#xff0c;避免弯路&#xff01;***一&#xff0c;简单了解远程分支1&#xff0c;连接远程&#xff1a;2&#xff0c;提交&am…...

Answering Multi-Dimensional Range Queries under Local Differential Privacy

文章目录AbstractIntroduction2 PRELIMINARIES2.12.2 Categorical Frequency Oracles4 GRID APPROACHES4.1概述Abstract 在本文中&#xff0c;我们解决了在局部差异隐私下回答多维范围查询的问题。有三个关键的技术挑战&#xff1a;捕捉属性之间的相关性&#xff0c;避免维度的…...

手把手搭建springboot项目05-springboot整合Redis及其业务场景

目录前言一、食用步骤1.1 安装步骤1.1.1 客户端安装1.2 添加依赖1.3 修改配置1.4 项目使用1.5 序列化二、应用场景2.1 缓存2.2.分布式锁2.2.1 redis实现2.2.2 使用Redisson 作为分布式锁2.3 全局ID、计数器、限流2.4 购物车2.5 消息队列 (List)2.6 点赞、签到、打卡 (Set)2.7 筛…...

Flutter基础语法(六)var、final、const、late

Flutter基础 第六章 Flutter关键字var、final、const、late的区别与使用 文章目录Flutter基础前言一、var1.var是什么?2.var如何使用3.var自动推断类型4.var可以再次赋值5.var指定类型二、final1.final是什么?2.final声明但不赋值3.final赋值多次4.final正常使用三、const1.…...

Linux之安装node

Linux之安装node步骤如下 1.去网站下载node 下载地址&#xff1a; https://npm.taobao.org/mirrors/ 2.上传到指定目录下 3.解压 tar -zxvf node-v17.3.0-linux-x644.配置node环境变量 //执行以下命令 vim /etc/profile //在path中加入以下内容 /usr/local/node-v15.14.0/b…...

二叉树、二叉搜索树、二叉树的最近祖先、二叉树的层序遍历【零神基础精讲】

来源0x3f&#xff1a;https://space.bilibili.com/206214 文章目录二叉树[104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)[111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)[129. 求根节点到叶节点…...

【算法】【数组与矩阵模块】求最长可整合子数组和子数组的长度

目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过&#xff0c;但是不保证100%的测试用例&#xff0c;如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识&#xff01; 问题介绍 …...

数据结构:循环队列的实现(leetcode622.设计循环队列)

目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口 3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览 三.静态单向循环链表实现循环队列 1.链表循环队列的结构设计 2.创建静…...

[qiankun]实战问题汇总

[qiankun]实战问题汇总ERROR SyntaxError: Cannot use import statement outside a module问题分析解决方案子应用命名问题问题分析解决方案jsonpFunction详细错误信息问题分析解决方案微应用的注册问题Uncaught Error: application cli5-beta6-test-name died in status LOADI…...

Kafka(6):服务端常用参数配置

参数配置&#xff1a;config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership.…...

2023爱分析·云原生智能运维中台市场厂商评估报告:秒云(miaoyun.io)

目录 1. 研究范围定义 2. 云原生智能运维中台市场定义 3. 厂商评估&#xff1a;秒云&#xff08;miaoyun.io&#xff09; 4. 入选证书 1. 研究范围定义 数字化时代&#xff0c;应用成为企业开展各项业务的落脚点。随着业务的快速发展&#xff0c;应用的功能迭代变得越…...

hadoop容器化部署

1、原容器 java:openjdk-8u111-jre jre路径&#xff1a; /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/java-1.8.0-openjdk-amd64 2、安装ssh docker run -it --name hadoop-test java:openjdk-8u111-jre bash apt-get update apt-get install openssh service ssh start …...