【设计模式 - 18】之备忘录模式(Memento)
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】。