设计模式——备忘录模式

备忘录模式(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】结果展示:备份者模式思想相对简单,主要查看细节上的实现。备份类相对简单,就一个普通类。但是目标类,提供了存储原始对象和获取原始对象的方法,是备份者模式的精华所在。

 设计模式——备忘录模式设计模式——备忘录模式

 
上一篇:Luogu Daily & Original Blog (reproduced)


下一篇:LeetCode 1379. 找出克隆二叉树中的相同节点(二叉树遍历)