设计模式之备忘录模式

释放双眼,带上耳机,听听看~!

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.推荐阅读

给TA打赏
共{{data.count}}人
人已打赏
安全运维

MySQL和MongoDB数据相互迁移

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索