# 备忘录模式Memento
阅读量  loading 
 # 一、概念
# 1、定义
保存一个对象的某个状态,以便在适当的时候恢复对象。
# 2、补充
“后悔药”
# 3、类型
行为型
# 4、适用场景
- 保存及恢复数据相关业务场景
 - 后悔的时候,即想恢复到之前的状态
 
# 5、优点
- 为用户提供一种可恢复的机制
 - 存档信息的封装
 
# 6、缺点
资源占用
# 7、相关设计模式
- 备忘录模式和状态模式
 
备忘录模式是用实例表示状态,存的存档是一个对象的实例;状态模式是用类表示状态。
# 二、应用
首先创建一个笔记类:
public class Article {
    private String title;
    private String content;
    private String image;
    public Article(String title, String content, String image) {
        this.title = title;
        this.content = content;
        this.image = image;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public ArticleMemento saveToMemento() {
        ArticleMemento articleMemento = new ArticleMemento(title, content, image);
        return articleMemento;
    }
    public void undoFromMemento(ArticleMemento articleMemento) {
        this.title = articleMemento.getTitle();
        this.content = articleMemento.getContent();
        this.image = articleMemento.getImage();
    }
    @Override
    public String toString() {
        return "Article{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", image='" + image + '\'' +
                '}';
    }
}
 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
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
其中 saveToMemento() 就是保存笔记的方法,undoFromMemento() 就是还原的方法。
看下 ArticleMemento 类:
public class ArticleMemento {
    private String title;
    private String content;
    private String image;
    public ArticleMemento(String title, String content, String image) {
        this.title = title;
        this.content = content;
        this.image = image;
    }
    public String getTitle() {
        return title;
    }
    public String getContent() {
        return content;
    }
    public String getImage() {
        return image;
    }
    @Override
    public String toString() {
        return "ArticleMemento{" +
                "title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", image='" + image + '\'' +
                '}';
    }
}
 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
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
在看下 ArticleMementoManager 的管理类:
public class ArticleMementoManager {
    private final Stack<ArticleMemento> ARTICLE_MEMENTO_STACK = new Stack<>();
    public ArticleMemento getMemento() {
        return ARTICLE_MEMENTO_STACK.pop();
    }
    public void addMemento(ArticleMemento articleMemento) {
        ARTICLE_MEMENTO_STACK.push(articleMemento);
    }
}
 1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
类图:

测试类:
public class Test {
    public static void main(String[] args) {
        ArticleMementoManager articleMementoManager = new ArticleMementoManager();
        Article article = new Article("Java设计模式A", "内容A", "图片A");
        ArticleMemento articleMemento = article.saveToMemento();
        // 存档
        articleMementoManager.addMemento(articleMemento);
        System.out.println("原始:" + article);
        System.out.println("修改笔记 start");
        article.setTitle("Java设计模式B");
        article.setContent("内容B");
        article.setImage("图片B");
        System.out.println("修改笔记 end");
        System.out.println("修改1次后:" + article);
        articleMemento = article.saveToMemento();
        articleMementoManager.addMemento(articleMemento);
        article.setTitle("Java设计模式C");
        article.setContent("内容C");
        article.setImage("图片C");
        System.out.println("修改2次后:" + article);
        System.out.println("暂存回退 start");
        System.out.println("回退出栈1次");
        articleMemento = articleMementoManager.getMemento();
        article.undoFromMemento(articleMemento);
        System.out.println("回退1次:" + article);
        System.out.println("回退出栈2次");
        articleMemento = articleMementoManager.getMemento();
        article.undoFromMemento(articleMemento);
        System.out.println("暂存回退 end");
        System.out.println("回退2次:" + article);
    }
}
 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
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
执行结果:
原始:Article{title='Java设计模式A', content='内容A', image='图片A'}
修改笔记 start
修改笔记 end
修改1次后:Article{title='Java设计模式B', content='内容B', image='图片B'}
修改2次后:Article{title='Java设计模式C', content='内容C', image='图片C'}
暂存回退 start
回退出栈1次
回退1次:Article{title='Java设计模式B', content='内容B', image='图片B'}
回退出栈2次
暂存回退 end
回退2次:Article{title='Java设计模式A', content='内容A', image='图片A'}
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 三、源码中的应用
# spring 的 StateManageableMessageContext
StateManageableMessageContext 接口继承自 MessageContext,这个接口有3个方法:
public interface StateManageableMessageContext extends MessageContext {
	/**
	 * Create a serializable memento, or token representing a snapshot of the internal state of this message context.
	 * @return the messages memento
	 */
	public Serializable createMessagesMemento();
	/**
	 * Set the state of this context from the memento provided. After this call, the messages in this context will match
	 * what is encapsulated inside the memento. Any previous state will be overridden.
	 * @param messagesMemento the messages memento
	 */
	public void restoreMessages(Serializable messagesMemento);
	/**
	 * Configure the message source used to resolve messages added to this context. May be set at any time to change how
	 * coded messages are resolved.
	 * @param messageSource the message source
	 * @see MessageContext#addMessage(MessageResolver)
	 */
	public void setMessageSource(MessageSource messageSource);
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这就是使用了备忘录模式。
← 观察者模式 命令模式Command →