备忘录模式(Memento Pattern):保存对象的某个状态,以便在未来需要的时候进行数据的恢复。相当容易理解,举个简单的例子:Word 软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;
一、备忘录模式的基本介绍
【1】备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
【2】现实生活中备忘录是用来记录某些要去做的事情,或者是记录已经达成共同意见的事情,以防忘记。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作。
【3】备忘录模式属于行为型模式。
【4】实现了信息的封装,使得用户不需要关心状态和保存细节。符合 “单一职责原则” 。
【5】为了节约内存,备忘录模式可以和原型模式配合使用。
二、备忘录模式的结构与类图
忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类,备忘录模式的主要角色如下:
【1】发起人(Originator)角色:记录当前对象的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
【2】备忘录(Memetor)角色:负责存储发起人对象的内部状态,在需要的时候提供这些内部状态给发起人。
【3】管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
三、备忘录模式案例分析
我们使用备忘录模式写一个学校 100 米考试的案例:5 人一组,进行分组测试。我们需要备份的对象是,一组学生的成绩。
【1】发起人(Originator)角色:发起人需要依赖备忘录类,对自己每次记录的成绩进行备份 createMemento 。同时需要提供一个还原方法 getOriginalFromMemento 将需要的备份类作为参数传递进来,并将结果赋值给目标类。
1 //100 米 测试 5人一组 ,这是个人所花费的时间,我们使用备忘录的方式实现一下。 2 public class Original { 3 //姓名 4 private String name; 5 //时间 6 private int timestamp; 7 8 public Memento createMemento() { 9 return new Memento(name, timestamp); 10 } 11 //获取目标对象 通过排名 12 public void getOriginalFromMemento(Memento memento) { 13 name = memento.getName(); 14 timestamp = memento.getTimestamp(); 15 } 16 17 public int getTimestamp() { 18 return timestamp; 19 } 20 21 public void setTimestamp(int timestamp) { 22 this.timestamp = timestamp; 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 @Override 33 public String toString() { 34 return "Original [name=" + name + ", timestamp=" + timestamp + "]"; 35 } 36 }
【2】备忘录(Memetor)角色:提供一些目标对象需要备份的属性,通过构造器进行属性传递。
1 public class Memento { 2 //姓名 3 private String name; 4 //时间 5 private int timestamp; 6 7 //构造器 8 public Memento(String name, int timestamp) { 9 super(); 10 this.name = name; 11 this.timestamp = timestamp; 12 } 13 14 public String getName() { 15 return name; 16 } 17 18 public void setName(String name) { 19 this.name = name; 20 } 21 22 public int getTimestamp() { 23 return timestamp; 24 } 25 26 public void setTimestamp(int timestamp) { 27 this.timestamp = timestamp; 28 } 29 }
【3】管理者(Caretaker)角色:创建一个存储备忘录对象的集合 <Map、List、Set> 等,同时创建添加、获取、清空等方法。
1 public class Caretaker { 2 //排名 3 private int index = 1; 4 //用于顺序存储 参加测试的 十名同学的成绩 5 Map<Integer, Memento> mementos = new HashMap<Integer, Memento>(); 6 //提供一个 add 方法 7 public void add(Memento m) { 8 mementos.put(index, m); 9 index += 1; 10 } 11 //获取备份类 12 public Memento get(int key) { 13 return mementos.get(key); 14 } 15 //归位 16 public void remove() { 17 mementos.clear(); 18 } 19 }
【4】客户端(Client)角色:首先将顺序按的前五名同学的成绩及姓名,通过集合 Map 按照名次存储。五名同学测试完成后,通过目标类的 getOriginalFromMemento 方法,根据名次获取同学的成绩,并记录在成绩花名册中。最后,清空记录下一组。
1 public class Client { 2 public static void main(String[] args) { 3 //创建 目标类 4 Original original = new Original(); 5 //管理类 6 Caretaker managerMemento = new Caretaker(); 7 //记录成绩 8 recordResults(original,managerMemento); 9 //获取第一名的成绩 10 System.out.println("恢复前目标类的记录值"+original.toString()); 11 //从集合中获取第一名的值 12 Memento memento1 = managerMemento.get(1); 13 //调用目标类的还原方法 14 original.getOriginalFromMemento(memento1); 15 System.out.println("恢复第一名的成绩信息:"+original.toString()); 16 17 //从集合中获取第三名的值 18 Memento memento3 = managerMemento.get(3); 19 //调用目标类的还原方法 20 original.getOriginalFromMemento(memento3); 21 System.out.println("恢复第三名的成绩信息:"+original.toString()); 22 23 //清空记录下一组 24 managerMemento.remove(); 25 } 26 27 private static void recordResults(Original original,Caretaker managerMemento) { 28 //第一名学生成绩 29 original.setName("张三"); 30 original.setTimestamp(2330); 31 //创建一个备份类 32 Memento memento1 = original.createMemento(); 33 //备份类存入 管理类中 34 managerMemento.add(memento1); 35 36 //第二名学生成绩 37 original.setName("李四"); 38 original.setTimestamp(2550); 39 //创建一个备份类 40 Memento memento2 = original.createMemento(); 41 //备份类存入 管理类中 42 managerMemento.add(memento2); 43 44 //第三名学生成绩 45 original.setName("王五"); 46 original.setTimestamp(2560); 47 //创建一个备份类 48 Memento memento3 = original.createMemento(); 49 //备份类存入 管理类中 50 managerMemento.add(memento3); 51 } 52 }
【5】结果展示:备份者模式思想相对简单,主要查看细节上的实现。备份类相对简单,就一个普通类。但是目标类,提供了存储原始对象和获取原始对象的方法,是备份者模式的精华所在。