0x01.定义与类型
-
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
-
类型:行为型
-
UML类图
-
基本代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 1/**
2 * 发起人类
3 */
4public class Originator {
5
6 /**
7 * 状态编码
8 */
9 private String status;
10
11 public Originator(String status) {
12 this.status = status;
13 }
14
15 public String getStatus() {
16 return status;
17 }
18
19 public void setStatus(String status) {
20 this.status = status;
21 }
22
23 /**
24 * 创建备忘录
25 * @return
26 */
27 public Memento createMemento() {
28 return new Memento(this);
29 }
30
31 /**
32 * 回滚
33 * @param memento
34 */
35 public void restoreMemento(Memento memento) {
36 this.status = memento.getStatus();
37 }
38}
39
40/**
41 * 备忘录类
42 */
43public class Memento {
44
45 private String status;
46
47 public Memento(Originator originator) {
48 this.status = originator.getStatus();
49 }
50
51 public String getStatus() {
52 return status;
53 }
54
55 public void setStatus(String status) {
56 this.status = status;
57 }
58}
59
60/**
61 * 备忘录管理类
62 */
63public class Caretaker {
64
65 /**
66 * 备忘录记录栈
67 */
68 private Stack<Memento> MEMENTO_STACK;
69
70 public Caretaker() {
71 MEMENTO_STACK = new Stack<>();
72 }
73
74 /**
75 * 添加一个备忘录
76 * @param memento
77 */
78 public void addMemento(Memento memento) {
79 MEMENTO_STACK.push(memento);
80 }
81
82 /**
83 * 获取一个备忘录
84 * @return
85 */
86 public Memento getMemento() {
87 return MEMENTO_STACK.pop();
88 }
89
90}
91
92
-
测试与应用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 1/**
2 * 测试与应用
3 */
4public class Test {
5
6 public static void main(String[] args) {
7 //备忘录管理
8 Caretaker caretaker = new Caretaker();
9
10 //发起人
11 Originator originator = new Originator("1");
12
13 //创建备忘录1
14 Memento memento1 = originator.createMemento();
15 caretaker.addMemento(memento1);
16
17 //修改并创建备忘录2
18 originator.setStatus("2");
19 Memento memento2 = originator.createMemento();
20 caretaker.addMemento(memento2);
21
22 //修改状态3
23 originator.setStatus("3");
24 System.out.println(originator.getStatus());
25
26 //回滚上一次
27 originator.restoreMemento(caretaker.getMemento());
28 System.out.println(originator.getStatus());
29
30 //回滚上一次
31 originator.restoreMemento(caretaker.getMemento());
32 System.out.println(originator.getStatus());
33 }
34}
35
36
-
输出结果
1
2
3
4
5 13
22
31
4
5
-
备忘录模式角色介绍
-
发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
- 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
0x02.适用场景
- 需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
- 需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。
0x03.优缺点
1.优点
- 为用户提供一种可恢复机制
- 存档信息的封装
- 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
- 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
- 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
2.缺点
- 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
0x04.代码实现
在线编辑文章时,可以回退功能得备忘录模式实现。
- UML类图
-
代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 1/**
2 * 文章类
3 */
4public class Article {
5
6 //标题
7 private String title;
8
9 //内容
10 private String content;
11
12 //图片
13 private String images;
14
15 public Article(String title, String content, String images) {
16 this.title = title;
17 this.content = content;
18 this.images = images;
19 }
20
21 public String getTitle() {
22 return title;
23 }
24
25 public void setTitle(String title) {
26 this.title = title;
27 }
28
29 public String getContent() {
30 return content;
31 }
32
33 public void setContent(String content) {
34 this.content = content;
35 }
36
37 public String getImages() {
38 return images;
39 }
40
41 public void setImages(String images) {
42 this.images = images;
43 }
44
45 public ArticleMemento saveToMemento() {
46 return new ArticleMemento(this);
47 }
48
49 public void undoFromMemento(ArticleMemento articleMemento) {
50 this.title = articleMemento.getTitle();
51 this.content = articleMemento.getContent();
52 this.images = articleMemento.getImages();
53 }
54
55 @Override
56 public String toString() {
57 return "Article{" +
58 "title='" + title + '\'' +
59 ", content='" + content + '\'' +
60 ", images='" + images + '\'' +
61 '}';
62 }
63}
64
65/**
66 * 备忘录类
67 */
68public class ArticleMemento {
69
70 private String title;
71
72 private String content;
73
74 private String images;
75
76 public ArticleMemento(Article article) {
77 this.title = article.getTitle();
78 this.content = article.getContent();
79 this.images = article.getImages();
80 }
81
82 public String getTitle() {
83 return title;
84 }
85
86 public String getContent() {
87 return content;
88 }
89
90 public String getImages() {
91 return images;
92 }
93
94 @Override
95 public String toString() {
96 return "ArticleMemento{" +
97 "title='" + title + '\'' +
98 ", content='" + content + '\'' +
99 ", images='" + images + '\'' +
100 '}';
101 }
102}
103
104/**
105 * 备忘录管理类
106 */
107public class ArticleMementoManager {
108
109 private final Stack<ArticleMemento> ARTICLE_MEMENTO_STACK = new Stack<>();
110
111 public ArticleMemento getMemento () {
112 return ARTICLE_MEMENTO_STACK.pop();
113 }
114
115 public void addMemento(ArticleMemento articleMemento) {
116 ARTICLE_MEMENTO_STACK.push(articleMemento);
117 }
118
119}
120
121
-
测试与应用类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 1/**
2 * 测试与应用
3 */
4public class Test {
5
6 public static void main(String[] args) {
7 //创建备忘录管理
8 ArticleMementoManager articleMementoManager = new ArticleMementoManager();
9
10 Article article = new Article("如影随形的设计模式A", "内容A", "图片A");
11
12 ArticleMemento articleMemento = article.saveToMemento();
13
14 articleMementoManager.addMemento(articleMemento);
15
16 System.out.println(article.toString());
17
18 article.setTitle("修改手记start");
19 article.setContent("手记内容B");
20 article.setImages("手记图片B");
21
22 System.out.println(article);
23
24 articleMemento = article.saveToMemento();
25
26 articleMementoManager.addMemento(articleMemento);
27
28 article.setTitle("设计模式C");
29 article.setContent("手记内容C");
30 article.setImages("手记图片C");
31
32 System.out.println(article.toString());
33
34 System.out.println("回退出栈一次");
35 articleMemento = articleMementoManager.getMemento();
36 article.undoFromMemento(articleMemento);
37
38 System.out.println(article.toString());
39
40 System.out.println("回退出栈两次");
41 articleMemento = articleMementoManager.getMemento();
42 article.undoFromMemento(articleMemento);
43
44 System.out.println(article.toString());
45 }
46}
47
48
-
输出结果
1
2
3
4
5
6
7
8
9 1Article{title='design-pattern1', content='memento1', images='memento1'}
2Article{title='design-pattern2', content='memento2', images='memento2'}
3Article{title='design-pattern3', content='memento3', images='memento3'}
4pop stack 1.
5Article{title='design-pattern2', content='memento2', images='memento2'}
6pop stack 2.
7Article{title='design-pattern1', content='memento1', images='memento1'}
8
9
0x05.相关设计模式
-
备忘录模式和状态模式
-
备忘录:用实例表示状态
- 状态:用类来表示状态
0x06.源码中的备忘录模式
- spring webflow: StateManageableMessageContext
0x07.代码地址
0x08.推荐阅读
- 慕课网设计模式精讲:https://coding.imooc.com/class/270.html
- 备忘录模式(详尽版):http://c.biancheng.net/view/1400.html