备忘录设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !

目录

1.简介 2.什么是Memento设计模式 3.实施Memento设计模式 4.何时使用纪念图案 5. JDK中的Memento模式 6.下载源代码

1.简介

有时有必要记录对象的内部状态。 在实施检查点和“撤消”机制时,这是必需的,该机制使用户退出尝试性操作或从错误中恢复。 您必须将状态信息保存在某处,以便可以将对象还原到其先前的状态。 但是对象通常封装了部分或全部状态,使得其他对象无法访问它,并且无法在外部保存。 暴露此状态将违反封装,这可能会损害应用程序的可靠性和可扩展性。

可以使用Memento模式完成此操作,而无需暴露对象的内部结构。 需要捕获其状态的对象称为始发者。

为了说明Memento模式的用法,我们来看一个示例。 我们将创建一个包含两个双精度类型字段的类,并在其上运行一些数学运算。 我们将为用户提供撤消操作。 如果用户不满意某些操作后的结果,则用户可以调用撤消操作,该操作会将对象的状态恢复到最后保存的点。

该示例还包括一个保存点机制,用户可以使用该机制保存对象的状态。 我们还将提供各种撤消操作。 一个简单的撤消操作会将对象状态恢复到先前的保存点。 具有指定保存点的撤消将还原对象的特定状态,而全部撤消将删除对象的所有已保存状态,并在创建对象时将其恢复为初始化状态。

在实施模式之前,让我们进一步了解Memento设计模式。

2.什么是Memento设计模式

Memento模式的目的是在不违反封装的情况下捕获并外部化对象的内部状态,以便以后可以将对象恢复为该状态。

class_diagram_1

图1

纪念品

  • 存储原始对象的内部状态。 纪念品可以根据原始创建者的判断存储尽可能多的原始内部状态。
  • 防止发起者以外的对象访问。 备忘录有效地具有两个接口。 Caretaker看到与Memento的接口很狭窄-它只能将Memento传递给其他对象。 相反,Originator看到了一个广泛的接口,该接口使它可以访问将自身恢复到先前状态所需的所有数据。 理想情况下,仅允许产生纪念品的始发者访问纪念品的内部状态。

鼻祖

  • 创建一个包含其当前内部状态快照的纪念品。
  • 使用纪念品恢复其内部状态。

看守人

  • 负责纪念品的保管。
  • 切勿操作或检查纪念品的内容。

当客户端想要保存发起者的状态时,它向发起者请求当前状态。 发起方将恢复其状态所需的所有那些属性存储在称为Memento的单独对象中,并将其返回给客户端。 因此,在给定的时间点,可以将Memento视为包含另一个对象的内部状态的对象。 一个Memento对象必须对除原始者之外的所有对象隐藏原始者变量值。 换句话说,它应该保护其内部状态,以防止除原始方以外的其他对象访问。 为此,在允许始发者访问其内部状态的同时,应将Memento设计为提供对其他对象的受限访问。

当客户希望将发起者恢复到其先前的状态时,它只是将备忘录传递回发起者。 始发者使用包含在memento中的状态信息,并将自身返回到存储在Memento对象中的状态。

3.实施Memento设计模式

package com.javacodegeeks.patterns.mementopattern;public class Originator {private double x;private double y;private String lastUndoSavepoint;CareTaker careTaker;public Originator(double x, double y,CareTaker careTaker){this.x = x;this.y = y;this.careTaker = careTaker;createSavepoint("INITIAL");}public double getX(){return x;}public double getY(){return y;}public void setX(double x) {this.x = x;}public void setY(double y) {this.y = y;}public void createSavepoint(String savepointName){careTaker.saveMemento(new Memento(this.x, this.y), savepointName);lastUndoSavepoint = savepointName;}public void undo(){setOriginatorState(lastUndoSavepoint);}public void undo(String savepointName){setOriginatorState(savepointName);}public void undoAll(){setOriginatorState("INITIAL");careTaker.clearSavepoints();}private void setOriginatorState(String savepointName){Memento mem = careTaker.getMemento(savepointName);this.x = mem.getX();this.y = mem.getY();}@Overridepublic String toString(){return "X: "+x+", Y: "+y;}}

上面是Originator类,其对象状态应保存在内存中。 该类包含两个double类型的字段xy ,并且还引用了CareTaker 。 的CareTaker用来保存和检索代表该状态的纪念品对象Originator对象。

在构造函数中,我们使用createSavepoint方法保存了对象的初始状态。 此方法创建一个memento对象,并请求看护者照顾该对象。 我们使用了lastUndoSavepoint变量,该变量用于存储上次保存的lastUndoSavepoint的键名,以实现undo操作。

该类提供三种类型的undo操作。 不带任何参数的undo方法将还原最后保存的状态,以保存点名称作为参数的undo将还原使用该特定保存点名称保存的状态。 undoAll方法要求看护者清除所有保存点并将其设置为初始状态(创建对象时的状态)。

package com.javacodegeeks.patterns.mementopattern;public class Memento {private double x;private double y;public Memento(double x, double y){this.x = x;this.y = y;}public double getX(){return x;}public double getY(){return y;}
}

Memento类用于存储的状态Originator和照顾接受者存储。 该类没有任何设置方法,仅用于获取对象的状态。

package com.javacodegeeks.patterns.mementopattern;import java.util.HashMap;
import java.util.Map;public class CareTaker {private final Map<String, Memento>savepointStorage = new HashMap<String, Memento>();public void saveMemento(Memento memento,String savepointName){System.out.println("Saving state..."+savepointName);savepointStorage.put(savepointName, memento);}public Memento getMemento(String savepointName){System.out.println("Undo at ..."+savepointName);return savepointStorage.get(savepointName);}public void clearSavepoints(){System.out.println("Clearing all save points...");savepointStorage.clear();}}

上面的类是用于存储和提供请求的memento对象的看护者类。 该类包含saveMemento方法用于保存memento对象, getMemento方法用于返回请求memento对象,以及clearSavepoints方法用于清除所有保存点,并删除所有已保存的memento对象。

现在,让我们测试示例。

package com.javacodegeeks.patterns.mementopattern;public class TestMementoPattern {public static void main(String[] args) {CareTaker careTaker = new CareTaker();Originator originator = new Originator(5, 10, careTaker);System.out.println("Default State: "+originator);originator.setX(originator.getY()*51);System.out.println("State: "+originator);originator.createSavepoint("SAVE1");originator.setY(originator.getX()/22);System.out.println("State: "+originator);originator.undo();System.out.println("State after undo: "+originator);originator.setX(Math.pow(originator.getX(),3));originator.createSavepoint("SAVE2");System.out.println("State: "+originator);originator.setY(originator.getX()-30);originator.createSavepoint("SAVE3");System.out.println("State: "+originator);originator.setY(originator.getX()/22);originator.createSavepoint("SAVE4");System.out.println("State: "+originator);originator.undo("SAVE2");System.out.println("Retrieving at: "+originator);originator.undoAll();System.out.println("State after undo all: "+originator);}}

上面的代码将导致以下输出。

Saving state...INITIAL
Default State: X: 5.0, Y: 10.0
State: X: 510.0, Y: 10.0
Saving state...SAVE1
State: X: 510.0, Y: 23.181818181818183
Undo at ...SAVE1
State after undo: X: 510.0, Y: 10.0
Saving state...SAVE2
State: X: 1.32651E8, Y: 10.0
Saving state...SAVE3
State: X: 1.32651E8, Y: 1.3265097E8
Saving state...SAVE4
State: X: 1.32651E8, Y: 6029590.909090909
Undo at ...SAVE2
Retrieving at: X: 1.32651E8, Y: 10.0
Undo at ...INITIAL
Clearing all save points...
State after undo all: X: 5.0, Y: 10.0

在上面的代码中,我们创建了一个CareTaker对象,然后将其分配给Originator对象。 然后,将xy的值分别设置为5和10。然后,对x一些运算并将对象的状态保存为“ SAVE1”。

经过更多的操作后,我们调用了undo方法来恢复对象的最后状态,该状态在输出中会清楚显示。 然后,我们进行了一些操作,然后再次将对象的状态保存为“ SAVE2,SAVE3和SAVE4”。

然后,我们问Originator恢复SAVE2状态和呼叫undoAll方法,设置对象的初始状态,并删除所有保存点。

请注意,在以上示例中, Originator负责将其纪念品提供给看护者。 原因是我们不想将这种责任赋予用户。 在我们的示例中,用户只需要请求保存点和对象状态的恢复。 在许多情况下,看护人会由其他类别的人在发起人外部进行操作(如上图所示)。

4.何时使用纪念图案

在以下情况下,请使用Memento模式:

  • 必须保存对象状态(部分状态)的快照,以便以后可以将其恢复到该状态,并且
  • 获取状态的直接接口将公开实现细节并破坏对象的封装。

5. JDK中的Memento模式

  • java.util.Date
  • java.io.Serializable

6.下载源代码

这是关于Memento设计模式的课程。 您可以在此处下载源代码: MementoDesignPattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/memento-design-pattern.html

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

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

相关文章

打印机一直显示正在删除不掉怎么办?

1、停止打印服务&#xff0c;按WinR键打开运行对话框&#xff0c;然后输入“services.msc ” 打开任务管理。 找到“Print Spooler”&#xff0c;先停止该服务。 按WinR键打开运行对话框&#xff0c;然后输入“Spool” 回车打开“spool” 文件夹&#xff0c;打开“PRINTERS”文…

java 并发 面试_Java 并发基础常见面试题总结

1. 什么是线程和进程?1.1. 何为进程?进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一个 JVM…

javafx动画_JavaFX:创建Sprite动画

javafx动画到目前为止&#xff0c;尽管我的大多数文章都涉及JavaFX属性和绑定&#xff0c;但是今天我想写一讲我也致力于JavaFX运行时的另一部分&#xff1a;动画API。 在本文中&#xff0c;我将解释如何在JavaFX中编写自定义动画&#xff0c;以及如何使用这种方法为Sprite动画…

FZU Problem 2238 Daxia Wzc's problem

Daxia在2016年5月期间去瑞士度蜜月,顺便拜访了Wzc,Wzc给他出了一个问题&#xff1a; Wzc给Daxia等差数列A(0),告诉Daxia首项a和公差d; 首先让Daxia求出数列A(0)前n项和,得到新数列A(1); 然后让Daxia求出数列A(1)前n项和,得到新数列A(2); 接着让Daxia求出数列A(2)前n项和,得到新…

生成器设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

【转】从 ArcGIS for Desktop 发布地图服务

原文链接&#xff1a;http://resources.arcgis.com/zh-CN/help/tutorials/01z300000007000000.htm 本教程的目的是将地图服务直接从 ArcGIS for Desktop 发布到 ArcGIS for Server 中。本教程与名为“在 ArcMap 中准备您的 Web 地图”的上一教程类似&#xff0c;需要使用 ArcGI…

java 模块化osgi_OSGi简介–模块化Java

java 模块化osgiOSGi联盟是这种搁浅的管理机构&#xff0c;它始于1999年。其最初目标是为网络设备创建开放搁浅。 基于此思想&#xff0c;此规范也针对Java引入。 Eclipse在Java中是第一个。 他们于2004年6月推出了基于OSGi的Eclipse IDE。 OSGi是在Java中定义动态模块的方法。…

Train Problem I hdu 1022(栈)

http://acm.split.hdu.edu.cn/showproblem.php?pid1022 题意&#xff1a;给出火车的进站与出站顺序&#xff0c;判断是否可以按照给出的出站顺序出站。 #include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <…

Spring数据和Redis

本文是我们学院课程的一部分&#xff0c;标题为Redis NoSQL键值存储 。 这是Redis的速成班。 您将学习如何安装Redis并启动服务器。 此外&#xff0c;您将在Redis命令行中乱七八糟。 接下来是更高级的主题&#xff0c;例如复制&#xff0c;分片和集群&#xff0c;同时还介绍了…

史上最全的SpringMVC学习笔记

SpringMVC学习笔记---- 一、SpringMVC基础入门&#xff0c;创建一个HelloWorld程序 1.首先&#xff0c;导入SpringMVC需要的jar包。 2.添加Web.xml配置文件中关于SpringMVC的配置<!--configure the setting of springmvcDispatcherServlet and configure the mapping-->&…

shader weaver_Oracle通过邀请Weaver和Chin推动JavaFX向前发展

shader weaver昨天&#xff0c;我发布了愚人节帖子&#xff0c;内容涉及加入NASA协助探索红色大行星。 那篇文章与事实相距不远……美国宇航局开发的技术的所有细节都是100&#xff05;准确的。 哎呀&#xff0c;即使我辞职也是事实&#xff01; 唯一不正确的部分是我将加入的公…

mysql快速上手3

上一章给大家说的是数据库的视图&#xff0c;存储过程等等操作&#xff0c;这章主要讲索引&#xff0c;以及索引注意事项&#xff0c;如果想看前面的文章&#xff0c;url如下&#xff1a; mysql快速上手1mysql快速上手2索引简介 索引是对数据库表中一个或多个列&#xff08;例如…

python图像锐化_Python图像处理介绍--图像模糊与锐化

欢迎关注 “小白玩转Python”&#xff0c;发现更多 “有趣”引言在之前的文章中&#xff0c;我们讨论了边缘检测内核。在本文我们将讨论如何在图像上应用模糊与锐化内核&#xff0c;将这些内核应用到彩色图像上&#xff0c;同时保留核心图像。一如既往&#xff0c;我们从导入所…

Eclipse配置初始化(自用)

以上都是性能调优的配置&#xff0c;下面是其他常用的配置和优化 设置utf-8编码 window -> preferences -> General -> workplace中text file encoding改为utf-8 设置properties文件编码window -> preferences -> General -> Content Types —> Text —&g…

java bits_一段关于JAVA程序升级的问题(Changing bits)

展开全部import java.awt.Color;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.BorderFactory;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JTextField;import javax.…

java合并两个有序链表_JS实现的合并两个有序链表算法示例

本文实例讲述了JS实现的合并两个有序链表算法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。示例&#xff1a;输入&#xff1a;1->2->4, 1->3->4输出&…

外墙设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中&#xff0c;您将深入研究大量的设计模式&#xff0c;并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因&#xff0c;并了解何时以及如何应用模式中的每一个。 在这里查看 &#xff01; 目录 …

java 监控 native 内存_JVM NativeMemoryTracking 分析堆外内存泄露

Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据。NMT介绍工欲善其事必先利其器&#xff0c;我们先把相关需要的配置和工具介绍清楚&#xff0c;再通过例子来看看具体如何使用NMT。打开NMT…

Charles 从入门到精通

目录与版权 转载请保留顶部的 Charles 中国特惠内容&#xff0c;本文的内容主要包括&#xff1a; Charles 的简介如何安装 Charles将 Charles 设置成系统代理Charles 主界面介绍过滤网络请求截取 iPhone 上的网络封包截取 Https 通讯信息模拟慢速网络修改网络请求内容给服务器做…

java 批量验证_正则表达式批量验证函数

正则表达式批量验证函数function checkData(){//判断数据的正确性var idSpans new Array();idSpans[0] new Array("item_4","^[\\s\\S]{1,16}$","productName","商机名称应在1-16字以内","",true); idSpans[1] new Array(…