java设计模式学习之【备忘录模式】

文章目录

  • 引言
  • 备忘录模式简介
    • 定义与用途
    • 实现方式
  • 使用场景
  • 优势与劣势
  • 在Spring框架中的应用
  • 备忘录示例
  • 代码地址

引言

想象一下,你正在编辑一篇重要的文档,突然你意识到最近的一些更改实际上破坏了文档的结构。幸运的是,你的文本编辑器允许你撤销最近的操作,回到之前的状态。这种能力就像有一个时间机器,可以回到过去,撤销错误的决策。在软件开发中,我们经常需要这种“撤销”功能,备忘录模式为此提供了一种优雅的解决方案。

备忘录模式简介

定义与用途

备忘录模式(Memento Pattern)是一种行为型设计模式,它允许保存一个对象的某个状态,以便在未来某个时刻恢复。这个模式在用户需要撤销或恢复操作时特别有用,它通过引入备忘录对象来捕获和存储对象的内部状态,而不破坏其封装性。

实现方式

实现备忘录模式通常涉及以下几个关键组件:

  • 原发器(Originator):需要保存状态以便后续恢复的对象。
  • 备忘录(Memento):存储原发器对象的内部状态。
  • 看护者(Caretaker):负责保存备忘录,但不修改或检查其内容。

使用场景

备忘录模式适用于以下场景:

  • 当需要保存和恢复对象的历史状态时。
  • 当直接获取对象的状态会暴露其实现细节并破坏对象封装性时。

例如:

  1. 文本编辑器的撤销功能:用户可以撤销最近的编辑操作,并恢复到之前的文本状态。
  2. 游戏保存和加载:在游戏中保存当前进度,玩家可以在以后加载保存点继续游戏。
  3. 软件的快照功能:软件可以定期保存当前状态,以便在出现问题时恢复到工作状态

优势与劣势

  • 优势
    1. 提供了一种恢复状态的灵活方式,而无需暴露对象的内部结构。
    2. 可以简化原发器的职责,因为状态的保存和恢复由备忘录承担。
  • 劣势
    1. 如果用户不断创建备忘录,可能会占用大量内存。
    2. 管理备忘录的成本可能会很高,尤其是如果需要支持多次撤销时。

在Spring框架中的应用

在Spring框架中,虽然备忘录模式不像其他设计模式那样直接显现,但它的核心概念——即保存和恢复对象状态——在某些功能中得到了体现。以下是Spring框架中体现备忘录模式概念的一些方面:

1. Spring Web Flow
在Spring Web Flow中,备忘录模式的概念被用于管理Web应用中的页面流。在用户导航过程中,每个页面的状态都可以被保存,用户可以回退到之前的状态。这类似于备忘录模式中的保存和恢复状态的概念。

2. 事务管理
Spring的声明式事务管理允许你在开始一个事务时保存数据库的某种状态,并在事务完成时恢复这种状态。如果事务失败,Spring可以回滚到事务开始之前的状态,这与备忘录模式中保存对象状态以便恢复的概念相符。

3. Spring Security的认证和授权
在Spring Security中,用户的认证状态(如安全上下文)在用户会话中保存和恢复。虽然这不是传统意义上的备忘录模式,但它体现了备忘录模式的核心概念——保存和恢复对象的状态。

4. 配置和恢复Bean状态
Spring的BeanFactory和ApplicationContext容器允许定义、保存和恢复Bean的配置状态。这些状态信息(如Bean的属性和依赖关系)可以在容器启动时被加载,并在需要时恢复,这与备忘录模式的基本原理类似。

尽管这些应用可能不是备忘录模式的典型示例,但它们都采用了该模式的核心思想——即保存和恢复状态。这些机制在Spring框架中至关重要,有助于实现高效和可靠的状态管理。

备忘录示例

在这里插入图片描述
步骤 1:创建备忘录类

public class Memento {
   private String state;

   public Memento(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }    
}

Memento 类包含了对象的状态。它有一个方法 getState() 用于获取保存的状态。

步骤 2:创建原发器类

public class Originator {
   private String state;

   public void setState(String state){
      this.state = state;
   }

   public String getState(){
      return state;
   }

   public Memento saveStateToMemento(){
      return new Memento(state);
   }

   public void getStateFromMemento(Memento memento){
      state = memento.getState();
   }
}

Originator 类是要保存状态的对象。它创建备忘录来保存自己的状态,并从备忘录中恢复状态。

步骤 3:创建看护者类

import java.util.ArrayList;
import java.util.List;

public class CareTaker {
   private List<Memento> mementoList = new ArrayList<Memento>();

   public void add(Memento state){
      mementoList.add(state);
   }

   public Memento get(int index){
      return mementoList.get(index);
   }
}

CareTaker 类负责保存备忘录,并在需要时提供备忘录。它维护了一个备忘录列表。

步骤 4:使用看护者和原发器对象

public class MementoPatternDemo {
   public static void main(String[] args) {
   
      Originator originator = new Originator();
      CareTaker careTaker = new CareTaker();
      
      originator.setState("State #1");
      originator.setState("State #2");
      careTaker.add(originator.saveStateToMemento());
      
      originator.setState("State #3");
      careTaker.add(originator.saveStateToMemento());
      
      originator.setState("State #4");
      System.out.println("当前状态: " + originator.getState());        
      
      originator.getStateFromMemento(careTaker.get(0));
      System.out.println("第一次保存的状态: " + originator.getState());
      originator.getStateFromMemento(careTaker.get(1));
      System.out.println("第二次保存的状态: " + originator.getState());
   }
}

在这里插入图片描述

在这个演示类中,我们创建了一个原发器对象 originator 和一个看护者对象 careTaker。原发器对象更改其状态几次,并保存这些状态到备忘录。通过看护者对象,我们能够恢复原发器对象之前的状态。

这个示例演示了备忘录模式如何用于保存和恢复对象的状态,同时不暴露对象的内部结构。通过这种方式,可以实现如撤销功能这样的操作,而不影响对象的封装性

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes快速实战与核心原理剖析

K8S 概览 K8S 是什么 K8S 官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ K8S 是 Kubernetes 的全称&#xff0c;源于希腊语&#xff0c;意为“舵手”或“飞行员”。Kubernetes 是用于自动部署、扩缩和管理容器化应用程序的开源系统。 Kubernetes 源自 Google 15 年…

Ubuntu18.04安装GTSAM库并验证GTSAM是否安装成功(亲测可用)

在SLAM&#xff08;Simultaneous Localization and Mapping&#xff09;和SFM&#xff08;Structure from Motion&#xff09;这些复杂的估计问题中&#xff0c;因子图算法以其高效和灵活性而脱颖而出&#xff0c;成为图模型领域的核心技术。GTSAM&#xff08;Georgia Tech Smo…

【算法刷题】Day26

文章目录 1. 买卖股票的最佳时机含冷冻期题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码&#xff1a; 2. 替换所有的问号题干&#xff1a;算法原理&#xff1a;代码&#xff1a; 1. 买卖股票的最佳时机含冷冻…

从 Linux Crontab 到 K8s CronJob,定时任务正在经历怎样的变革

作者&#xff1a;黄晓萌(学仁) 背景 Job 表示短周期的作业&#xff0c;定时 Job 表示按照预定的时间运行Job&#xff0c;或者按照某一频率周期性的运行 Job。比如&#xff1a; 许多传统企业使用 Linux 自带的 crontab 来做定时任务的方案&#xff0c;该方案非常简单&#xff…

laravel api资源的问题记录

resource 转换层 可以帮助我们转换一些字段的结果&#xff0c;类似前端的filter。 可以使用比如对象或者模型的形式来处理&#xff0c;但使用sql查询会导致n1的问题。如图&#xff1a; 层次嵌套很多&#xff0c;而且很深&#xff0c;这样虽然开发方便了&#xff0c;但是维护就…

Zblog主题模板:ZblogitseanPage博客主题模板

zblog主题模板&#xff1a;ZblogitseanPage博客主题模板 ZblogitseanPage博客主题模板主要是以文字内容为主导&#xff0c;将页面的设计杂乱的图片和元素进行最小化或者去除&#xff0c;从而使整个页面更加简洁、清晰&#xff0c;突出信息的呈现。 下面介绍一下zblog主题模板:Z…

【力扣】20.有效的括号

家人们&#xff0c;看这排序&#xff0c;一看就很简单&#xff0c;对吧&#xff1f;不对&#xff0c;我觉得还挺不是很容易的&#xff0c;哈哈哈。 题解&#xff1a; 在看题目的时候&#xff0c;我一开始的解题思路就挺复杂的。题目说了”左括号必须以正确的顺序闭合“&#x…

如何在简历中解释就业空白

您的工作经历有空缺吗&#xff1f;你不是一个人。有很多合理的理由可以解释为什么你需要休息一下。更重要的是&#xff0c;在一份真实正确的简历中&#xff0c;这些问题是无法避免的。直接解释就业差距总是更好&#xff0c;而且有很多因素需要考虑。你未来的老板想要了解工作轨…

【数据结构二】手撕顺序表与ArrayList源码详解

目录 顺序表与ArrayList 1. 手撕顺序表 2.ArrayList的使用 3.ArrayList的源码分析&#xff08;扩容机制&#xff09; 4.力扣题练习 顺序表与ArrayList 线性表是在逻辑上具备线性结构的一种有序序列&#xff0c;包括顺序表和链表。其中顺序表的物理地址也连续&#xff0c;一…

01_软件测试

01_软件测试 学习目标 1、能复述软件测试的定义 2、能说出7种测试分类的区别 3、能说出质量模型的重点5项 4、能说出测试流程的6个步骤 5、能说出测试模板8个要素 认识软件及测试 什么是软件 软件&#xff1a;控制计算机硬件工作的工具 软件的基本组成 软件生产过程 什么是软…

打地鼠游戏来了

主要利用js鼠标点击事件和window.setInterval&#xff08;&#xff09;回调函数来进行实现的. 源码获取方式&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1eW9qvX3zFH9qlH82-I4yOA 提取码&#xff1a;1233

配置代理解决跨域(CORS)问题

一、跨域 &#xff1f; 我们在完成前后端分离项目时&#xff08;VueSpringBoot&#xff09;&#xff0c;有很多人会遇到跨域问题&#xff08;CORS&#xff09;。 跨域&#xff08;Cross-Origin Resource Sharing&#xff0c;CORS&#xff09;是浏览器的一项安全功能&#xff…

Illustrator脚本 #015 自动角线

这是一个在画板上自动生成辅助线和角线的脚本,只要单击最右边按钮运行脚本即可。 绿色的为参考线及出血线。 #target "Illustrator" var settings = {addTrim : true,addBleedGuide : true,addCenterGuide : true,addCover : false,overlapAlert : false,trimma…

《数据库开发实践》之触发器

一、什么是触发器&#xff1f; 1.概念&#xff1a; 简单来说触发器就是一种特殊的存储过程&#xff0c;在数据库服务器触发事件的时候会自动执行其SQL语句集。 2.构成四要素&#xff1a; &#xff08;1&#xff09;名称&#xff1a;要符合标识符命名规则 &#xff08;2&am…

理解io/nio/netty

一、io io即input/output&#xff0c;输入和输出 1.1 分类 输入流、输出流&#xff08;按数据流向&#xff09; 字节流&#xff08;InputStream/OutputStream&#xff08;细分File/Buffered&#xff09;&#xff09;、字符流(Reader/Writer&#xff08;细分File/Buffered/pu…

How to Develop Word Embeddings in Python with Gensim

https://machinelearningmastery.com/develop-word-embeddings-python-gensim/ 本教程分为 6 个部分;他们是&#xff1a; 词嵌入 Gensim 库 开发 Word2Vec 嵌入 可视化单词嵌入 加载 Google 的 Word2Vec 嵌入 加载斯坦福大学的 GloVe 嵌入 词嵌入 单词嵌入是一种提供单词的…

git 如何将某个分支的某个提交复制到另外一个分支

请直接去看原文: 原文链接:git 如何将某个分支的某个提交复制到另外一个分支_gitlab里面的markdown文件可以复用其他分支的吗-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------…

删除数据后, redis 内存占用还是很高怎么办?

现象&#xff1a; reids 做了数据删除&#xff0c;数据量不大&#xff0c;使用 top 命令看&#xff0c;发现还是占用大量内存 原因&#xff1a; 1.redis 底层内存根据内存分配器分配&#xff0c;不会立刻释放 2.redis 释放的内存空间不是连续的&#xff0c;存在碎片 内存碎…

算法基础day2

前缀和 #include <iostream> using namespace std; const int N100010; int n,m; int a[N],s[N]; int main() {scanf("%d%d",&n,&m);for(int i1;i<n;i) scanf("%d",&a[i]);for(int i1;i<n;i) s[i]s[i-1]a[i];while(m--){int l,r;s…

HTML-基础知识-基本结构,注释,文档说明,字符编码(一)

1.超文本标记语言不分大小写。 2.超文本标签属性名和属性值不区分大小写。 3.超文本标签属性值重复&#xff0c;听取第一个。 4.html结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"vi…