1、模式简介

备忘录模式的定义:

  备忘录模式保存一个对象的某个状态,以便在适当的时候恢复对象,用作“后悔药”,即取消上次操作或返回到以前的某个版本。

备忘录模式的应用实例:

  • Windows系统中的Ctrl+Z;
  • 浏览器等软件中的后退按钮功能;
  • 数据库的事务管理及回滚功能;
  • 游戏存档。

备忘录模式的优点:

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

备忘录模式的缺点:

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

使用备忘录模式的注意事项:

  在使用备忘录模式的时候,为了节约内存,一般会将原型模式和备忘录模式结合起来使用。

2、案例

  本案例模拟数据库中的回滚功能。我们将创建一个类来管理对User用户表的操作。具体代码如下:

  备忘录管理类UserCaretaker中的代码如下:

import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 备忘录管理类,其中存储所有曾经操作后的数据,单例
*/
public class UserCaretaker {
private static UserCaretaker instance; // 单例对象 // 存储所有用户备忘录的集合,key是回滚点名称,value是备忘录对象
private Map<String, List<HashMap<String, String>>> mementoes; private UserCaretaker() {
this.mementoes = new HashMap<>();
} // 单例方法
public static UserCaretaker getInstance() {
if (instance == null) {
synchronized (UserCaretaker.class) {
if (instance == null) {
instance = new UserCaretaker();
}
}
}
return instance;
} // 添加备忘录
public void saveMemento(String name, List<HashMap<String, String>> memento) {
if (!mementoes.containsKey(name)) {
mementoes.put(name, memento);
}
} // 取出某个备忘录
public List<HashMap<String, String>> rollbackMemento(String name) {
if (mementoes.containsKey(name)) {
return mementoes.get(name);
}
return null;
}
}

  测试类Test中的代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; public class Test {
public static void main(String[] args) {
// 创建备忘录集合类
UserCaretaker caretaker = UserCaretaker.getInstance();
// 创建用户表
List<HashMap<String, String>> table1 = new ArrayList<>(); // 向表中添加数据
table1.add(makeMap("Jack", "20", "Beijing"));
table1.add(makeMap("Rose", "16", "Shanghai"));
table1.add(makeMap("Tom", "22", "Nanjing"));
table1.add(makeMap("David", "10", "Qingdao"));
// 存储为备忘录
caretaker.saveMemento("data_added", table1);
// 打印表中的数据
System.out.println("--------------初始化数据表---------------");
selectAllFromTable(table1); // 修改表中的数据
List<HashMap<String, String>> table2 = copyList(table1);
updateData(table2, "Rose", "88", "America");
// 存储为备忘录
caretaker.saveMemento("rose_updated", table2);
// 打印表中的数据
System.out.println("--------------修改表中数据---------------");
selectAllFromTable(table2); // 删除表中的数据
List<HashMap<String, String>> table3 = copyList(table2);
deleteData(table3, "Tom");
// 存储为备忘录
caretaker.saveMemento("tom_deleted", table3);
// 打印表中的数据
System.out.println("--------------删除表中数据---------------");
selectAllFromTable(table3); // 回滚到data_added节点
List<HashMap<String, String>> t = caretaker.rollbackMemento("data_added");
// 存储为备忘录
caretaker.saveMemento("rollback_add", t);
// 打印表中的数据
System.out.println("--------------回滚到data_added节点---------------");
selectAllFromTable(t);
} // 根据提供的数据生成一条数据
private static HashMap<String, String> makeMap(String name, String age, String address) {
HashMap<String, String> map = new HashMap<>();
map.put("name", name);
map.put("age", age);
map.put("address", address);
return map;
} // 更新一条数据
private static void updateData(List<HashMap<String, String>> table, String name, String age, String address) {
for (HashMap<String, String> map : table) {
if (map.get("name").equals(name)) {
map.put("age", age);
map.put("address", address);
}
}
} // 删除一条数据
private static void deleteData(List<HashMap<String, String>> table, String name) {
for (HashMap<String, String> map : table) {
if (map.get("name").equals(name)) {
table.remove(map);
}
}
} // SELECT * FROM tb_user
public static void selectAllFromTable(List<HashMap<String, String>> table) {
System.out.println("name\t\tage\taddress");
for (HashMap<String, String> user : table) {
System.out.println(user.get("name") + "\t\t" + user.get("age") + "\t" + user.get("address"));
}
System.out.println();
} // 复制一个List(List不能用“=”赋值,只能复制)
public static List<HashMap<String, String>> copyList(List<HashMap<String, String>> table) {
List<HashMap<String, String>> list = new ArrayList<>();
for (HashMap<String, String> map : table) {
HashMap<String, String> m = new HashMap<>();
m.put("name", map.get("name"));
m.put("age", map.get("age"));
m.put("address", map.get("address"));
list.add(m);
}
return list;
}
}

  运行结果如下图所示:

  最后贴出备忘录模式的GitHub代码地址:【GitHub - Memento】

【设计模式 - 18】之备忘录模式(Memento)的更多相关文章

  1. 《JAVA设计模式》之备忘录模式(Memento)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述备忘录(Memento)模式的: 备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式. 备忘录 ...

  2. 第18章 备忘录模式(Memento Pattern)

    原文  第18章 备忘录模式(Memento Pattern) 备忘录模式       概述: 备忘录模式(Memento Pattern)又叫做快照模式(Snapshot Pattern)或Toke ...

  3. 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern)

    原文:乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) 作者:webabc ...

  4. 备忘录模式 Memento 快照模式 标记Token模式 行为型 设计模式(二十二)

    备忘录模式 Memento   沿着脚印,走过你来时的路,回到原点.     苦海翻起爱恨   在世间难逃避命运   相亲竟不可接近   或我应该相信是缘份   一首<一生所爱>触动了多少 ...

  5. Java 设计模式系列(十八)备忘录模式(Memento)

    Java 设计模式系列(十八)备忘录模式(Memento) 备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式.备忘录对象是一个用来存储另外一个对象内部状态 ...

  6. 设计模式之备忘录模式(Memento)

    备忘录模式(Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. Originator(发起人):负责创建一个备忘录 ...

  7. 设计模式学习之备忘录模式(Memento,行为型模式)(19)

    假如我们已经记录一个人的个人信息,但是发现信息写错了,然后我先备份下再去修改,结果发现原来的信息是正确的,于是我就看备份的个人信息还原到初始的状态,下面我们用代码去实现 class Program { ...

  8. 二十四种设计模式:备忘录模式(Memento Pattern)

    备忘录模式(Memento Pattern) 介绍在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到保存的状态. 示例有一个Message实体类,某 ...

  9. 重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

    作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 实现不了是研发的借口? 实现不了,有时候是功能复杂度较高难以实 ...

  10. 备忘录模式-Memento Pattern(Java实现)

    备忘录模式-Memento Pattern Memento备忘录设计模式是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到以前保存的状态. 本文中的场景: 有一款游戏可以随时存档, ...

随机推荐

  1. markdown2 在win10下无法预览解决方案

    今天升级完Win10发现心爱的markdownPad 2无法预览,显示the view has crashed! 按照官网的Q&A http://markdownpad.com/faq.htm ...

  2. etTimeout与setInterval方法的区别

    etTimeout与setInterval方法的区别 setTimeout()用于设定在指定的时间之后执行对应的函数或代码.,在全局作用域下执行 setTimeout(code,time[,args… ...

  3. 【Java多线程与并发库】4.传统线程同步通信技术

    我们先通过一道面试题来了解传统的线程同步通信. 题目:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次,请写出程序. 我没有看答案, ...

  4. linux shell获取时间

    获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...

  5. 最常见的HTTP错误

    1. HTTP 500错误(内部服务器错误)对对HTTP 500错误的定义已经充分证明了这是一个最常见的HTTP错误. 一般来说,HTTP 500 错误就是web服务器发生内部错误时返回的信息. 例如 ...

  6. Linux进程和进程边界

    1. 进程和线程 2. 手机操作系统的发展 3. 进程的地址空间边界 4. 进程边界的安全围栏: Crash的不可扩延性 5. 进程边界的安全围栏: 全局数据和服务的不可访问性 http://www. ...

  7. 在Swift中使用libxml2

    // // main.swift // C150805_libxml2r2 // http://git.oschina.net/yao_yu/Swift2015/tree/master/C150805 ...

  8. EQueue 2.3.2

    EQueue 2.3.2版本发布(支持高可用) 前言 前段时间针对EQueue的完善终于告一段落了,实在值得庆祝,自己的付出和坚持总算有了成果.这次新版本主要为EQueue实现了集群功能,基本实现了B ...

  9. 安卓天天练练(十五)改造BasicSyncAdapter

    谷歌的官方示例BasicSyncAdapter是Android Studio工程, 把它依样画葫芦到Eclipse上,然后改造成我需要的样式. 看官方示例源码的时候,看到EntryListActivi ...

  10. Android 文件上传 使用AsyncHttpClient开源框架

    public void upload(View view) { AsyncHttpClient client = new AsyncHttpClient(); RequestParams reques ...