原文地址:折腾Java设计模式之备忘录模式

备忘录模式

Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later.

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

所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。通过一个备忘录类专门存储对象状态。客户不与备忘录类耦合,与备忘录管理类耦合。

备忘录模式UML

UML类图

Caretaker类是指用于保存(createMemento())和还原(restore(memento))发起方内部状态的Originator类。

发起方类实现

(1)createMemento(),通过创建和返回存储发起方当前内部状态的memento对象

(2)通过从传入的memento对象还原状态来还原(memento)。

UML时序图

(1)保存发起人的内部状态:Caretaker对Originator调用createMemento(),创建memento对象,保存其当前内部状态(setState()),并将memento返回给Caretaker。

(2)恢复发起人的内部状态:Caretaker对Originator调用restore(memento),并指定存储应恢复状态的memento对象。发起者从memento获取状态(getState())以设置其自己的状态。

备忘录模式角色结构

(1) 备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。

(2) 备忘发起(Originator)角色:“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。

(3) 备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。

干货示例

源码地址

public class Caretaker {

​    public static void main(String[] args) {
​ List<Memento> savedStates = new ArrayList();
​ Originator originator = new Originator();
​ originator.set("State1");
​ originator.set("State2");
​ savedStates.add(originator.saveToMemento()); ​ originator.set("State3");
​ savedStates.add(originator.saveToMemento()); ​ originator.set("State4");
​ originator.restoreFromMemento(savedStates.get(1));
​ }
} @Slf4j
public class Originator { ​ private String state; ​ //状态更改
​ public void set(String state) {
​ this.state = state;
​ log.info("Originator: Setting state to {}", state);
​ } ​ //将状态保存到备忘录里
​ public Memento saveToMemento() {
​ log.info("Originator: Saving to Memento.");
​ return new Memento(this.state);
​ } ​ //从备忘录里取出状态并回滚
​ public void restoreFromMemento(Memento memento) {
​ this.state = memento.getState();
​ log.info("Originator: State after restoring from Memento: {}", state);
​ }
} @Data
@AllArgsConstructor
public class Memento { ​ //状态维护
​ private String state; }

示例结果

从上述代码中看的出,随着状态变更,用List维护发起者的状态列表,从备忘录中取出状态以便回退状态。

java中的使用

生成对象状态的一个快照,以便对象可以恢复原始状态而不用暴露自身的内容。Date对象通过自身内部的一个long值来实现备忘录模式。

java.util.Date

java.io.Serializable

总结

优点

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

缺点

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

使用场景

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

注意事项

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

参考

备忘录模式|菜鸟教程

Memento pattern

细数JDK里的设计模式

欢迎关注

折腾Java设计模式之备忘录模式的更多相关文章

  1. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

  2. 折腾Java设计模式之状态模式

    原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...

  3. 折腾Java设计模式之模板方法模式

    博客原文地址:折腾Java设计模式之模板方法模式 模板方法模式 Define the skeleton of an algorithm in an operation, deferring some ...

  4. 折腾Java设计模式之访问者模式

    博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...

  5. 折腾Java设计模式之命令模式

    博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...

  6. java设计模式之备忘录模式

    备忘录模式 备忘录模式是一种软件设计模式:在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态.一听到备忘录这个字的时候想起了小小时打的游 ...

  7. 折腾Java设计模式之迭代器模式

    迭代器模式 Provide a way to access the elements of an aggregate object sequentially without exposing its ...

  8. java设计模式9.备忘录模式、访问者模式、调停者模式

    备忘录模式 备忘录模式又叫快照模式,备忘录对象是一个用来存储另外一个对象内部状态快照的对象.备忘录的用意是在不破坏封装的条件下,将一个对象的状态捕捉,并外部化存储起来,从而可以在将来合适的时候把这个对 ...

  9. Java设计模式应用——备忘录模式

    备忘录模式主要用于存档.游戏中我们打boss前总会存档,如果打boss失败,则读取存档,重新挑战boss. 可以看出来,备忘录模式一般包括如下数据结构 1. 存档文件:用于恢复备份场景的必要数据: 2 ...

随机推荐

  1. mysql实现主从备份

    mysql 主从备份的原理: 主服务器在做数据库操作的时候将所有的操作通过日志记录在binlog里面,有专门的文件存放.如localhost-bin.000003,这种,从服务器 和主服务配置好关系后 ...

  2. Wmyskxz文章目录导航附Java精品学习资料

    前言:这段时间一直在准备校招的东西,所以一晃眼都好长时间没更新了,这段时间准备的稍微好那么一点点,还是觉得准备归准备,该有的学习节奏还是要有..趁着复习的空隙来整理整理自己写过的文章吧..好多加了微信 ...

  3. netcore使用 jenkins + supervisor 实现standalone下多副本自动化发布

    上一篇我们用jenkins做了一个简单的自动化发布,在shell中采用的是 BUILD_ID=dontKillMe nohup dotnet xxx.dll &  这种简单的后台承载,如果你的 ...

  4. web scraper 抓取网页数据的几个常见问题

    如果你想抓取数据,又懒得写代码了,可以试试 web scraper 抓取数据. 相关文章: 最简单的数据抓取教程,人人都用得上 web scraper 进阶教程,人人都用得上 如果你在使用 web s ...

  5. Java设置PDF有序、无序列表

    文档中的设置有序或无序列表是一种反应内容上下级关系或者内容相同属性的方式,与单纯的文字叙述相比,它能有效增强文档内容的条理性,突出重点.因此,本文将分享通过Java编程在PDF文档中设置有序或无序列表 ...

  6. mysql 多实例部署

    Centos7.6 部署3个Mariadb 实例 [root@localhost ~]# yum install mariadb-server -y # 创建对应的目录文件 [root@localho ...

  7. ES6数组扩展运算符

    1 扩展运算符的运用 (1)复制数组 数组是复合的数据类型,直接复制的话,只是复制了指向底层数据机构的指针,而不是克隆一个全新的数组; const a1=[1,2]; const a2= a1; a2 ...

  8. osi参考模型(开放系统互连参考模型)

    自互联网诞生以来,随着网络飞速发展,用户迫切要求能在不同体系结构的网络空间交换信息,使得不同的网络能够互联起来. 国际化标准组织(International Organization for Stan ...

  9. react native中使用echarts

    开发平台:mac pro node版本:v8.11.2 npm版本:6.4.1 react-native版本:0.57.8 native-echarts版本:^0.5.0 目标平台:android端收 ...

  10. CASE 表达式

    通过本篇文章我们来学习一下CASE表达式的基本使用方法. CASE表达式有简单 CASE表达式(simple case expression)和搜索 CASE表达式(searched caseexpr ...