备忘录模式(Memento Pattern)详解

什么是备忘录模式

备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。

备忘录模式解决的问题

备忘录模式主要解决以下问题:

  1. 状态保存与恢复:需要保存对象在某一时刻的状态,以便在将来的某个时候恢复到该状态
  2. 封装性保护:在保存和恢复状态的同时,不破坏对象的封装性
  3. 状态管理:避免将对象的状态暴露给其他对象
  4. 撤销操作:实现撤销(Undo)和重做(Redo)功能
  5. 历史记录:记录对象的历史状态,以便回溯

备忘录模式的好处

  1. 状态封装:将对象的状态封装在备忘录中,不暴露给其他对象
  2. 状态管理:集中管理对象的状态,避免状态散落在代码各处
  3. 撤销/重做:轻松实现撤销和重做功能
  4. 简化代码:将状态保存和恢复的逻辑与业务逻辑分离
  5. 符合设计原则:遵循单一职责原则和封装原则

备忘录模式的结构

备忘录模式包含以下几个角色:

  1. 原发器(Originator):创建一个备忘录,记录当前状态;使用备忘录恢复状态
  2. 备忘录(Memento):存储原发器的内部状态
  3. 管理者(Caretaker):负责保存备忘录,不操作或检查备忘录的内容

各语言实现

C++ 实现

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
#include <iostream>
#include <string>
#include <vector>

// 备忘录类
class Memento {
private:
std::string state;
friend class Originator; // 允许 Originator 访问私有成员

Memento(const std::string& s) : state(s) {}

std::string getState() const {
return state;
}

public:
// 禁止外部修改状态
std::string getStateInfo() const {
return "Memento状态: " + state;
}
};

// 原发器类
class Originator {
private:
std::string state;

public:
void setState(const std::string& s) {
state = s;
std::cout << "设置状态: " << state << std::endl;
}

std::string getState() const {
return state;
}

// 创建备忘录
Memento createMemento() {
return Memento(state);
}

// 从备忘录恢复状态
void restoreMemento(const Memento& m) {
state = m.getState();
std::cout << "恢复状态: " << state << std::endl;
}
};

// 管理者类
class Caretaker {
private:
std::vector<Memento> mementos;

public:
void addMemento(const Memento& m) {
mementos.push_back(m);
std::cout << "保存状态" << std::endl;
}

Memento getMemento(int index) {
if (index >= 0 && index < mementos.size()) {
return mementos[index];
}
throw std::out_of_range("索引超出范围");
}

size_t getMementoCount() const {
return mementos.size();
}
};

// 客户端代码
int main() {
Originator originator;
Caretaker caretaker;

// 改变状态并保存
originator.setState("状态1");
caretaker.addMemento(originator.createMemento());

originator.setState("状态2");
caretaker.addMemento(originator.createMemento());

originator.setState("状态3");
std::cout << "当前状态: " << originator.getState() << std::endl;

// 恢复到之前的状态
std::cout << "\n恢复到状态1:" << std::endl;
originator.restoreMemento(caretaker.getMemento(0));

std::cout << "\n恢复到状态2:" << std::endl;
originator.restoreMemento(caretaker.getMemento(1));

return 0;
}

Java 实现

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
import java.util.ArrayList;
import java.util.List;

// 备忘录类
class Memento {
private String state;

// 只允许 Originator 创建 Memento
Memento(String state) {
this.state = state;
}

// 只允许 Originator 访问状态
String getState() {
return state;
}

// 提供公开的状态信息方法
public String getStateInfo() {
return "Memento状态: " + state;
}
}

// 原发器类
class Originator {
private String state;

public void setState(String state) {
this.state = state;
System.out.println("设置状态: " + state);
}

public String getState() {
return state;
}

// 创建备忘录
public Memento createMemento() {
return new Memento(state);
}

// 从备忘录恢复状态
public void restoreMemento(Memento memento) {
this.state = memento.getState();
System.out.println("恢复状态: " + state);
}
}

// 管理者类
class Caretaker {
private List<Memento> mementos = new ArrayList<>();

public void addMemento(Memento memento) {
mementos.add(memento);
System.out.println("保存状态");
}

public Memento getMemento(int index) {
if (index >= 0 && index < mementos.size()) {
return mementos.get(index);
}
throw new IndexOutOfBoundsException("索引超出范围");
}

public int getMementoCount() {
return mementos.size();
}
}

// 客户端代码
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();

// 改变状态并保存
originator.setState("状态1");
caretaker.addMemento(originator.createMemento());

originator.setState("状态2");
caretaker.addMemento(originator.createMemento());

originator.setState("状态3");
System.out.println("当前状态: " + originator.getState());

// 恢复到之前的状态
System.out.println("\n恢复到状态1:");
originator.restoreMemento(caretaker.getMemento(0));

System.out.println("\n恢复到状态2:");
originator.restoreMemento(caretaker.getMemento(1));
}
}

Python 实现

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
# 备忘录类
class Memento:
def __init__(self, state):
self._state = state # 私有属性

def get_state(self):
"""只允许 Originator 访问"""
return self._state

def get_state_info(self):
"""提供公开的状态信息"""
return f"Memento状态: {self._state}"

# 原发器类
class Originator:
def __init__(self):
self._state = ""

def set_state(self, state):
self._state = state
print(f"设置状态: {state}")

def get_state(self):
return self._state

def create_memento(self):
"""创建备忘录"""
return Memento(self._state)

def restore_memento(self, memento):
"""从备忘录恢复状态"""
self._state = memento.get_state()
print(f"恢复状态: {self._state}")

# 管理者类
class Caretaker:
def __init__(self):
self._mementos = []

def add_memento(self, memento):
self._mementos.append(memento)
print("保存状态")

def get_memento(self, index):
if 0 <= index < len(self._mementos):
return self._mementos[index]
raise IndexError("索引超出范围")

def get_memento_count(self):
return len(self._mementos)

# 客户端代码
if __name__ == "__main__":
originator = Originator()
caretaker = Caretaker()

# 改变状态并保存
originator.set_state("状态1")
caretaker.add_memento(originator.create_memento())

originator.set_state("状态2")
caretaker.add_memento(originator.create_memento())

originator.set_state("状态3")
print(f"当前状态: {originator.get_state()}")

# 恢复到之前的状态
print("\n恢复到状态1:")
originator.restore_memento(caretaker.get_memento(0))

print("\n恢复到状态2:")
originator.restore_memento(caretaker.get_memento(1))

C# 实现

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
using System;
using System.Collections.Generic;

// 备忘录类
class Memento {
private string state;

// 只允许 Originator 创建 Memento
internal Memento(string state) {
this.state = state;
}

// 只允许 Originator 访问状态
internal string GetState() {
return state;
}

// 提供公开的状态信息方法
public string GetStateInfo() {
return $"Memento状态: {state}";
}
}

// 原发器类
class Originator {
private string state;

public void SetState(string state) {
this.state = state;
Console.WriteLine($"设置状态: {state}");
}

public string GetState() {
return state;
}

// 创建备忘录
public Memento CreateMemento() {
return new Memento(state);
}

// 从备忘录恢复状态
public void RestoreMemento(Memento memento) {
this.state = memento.GetState();
Console.WriteLine($"恢复状态: {state}");
}
}

// 管理者类
class Caretaker {
private List<Memento> mementos = new List<Memento>();

public void AddMemento(Memento memento) {
mementos.Add(memento);
Console.WriteLine("保存状态");
}

public Memento GetMemento(int index) {
if (index >= 0 && index < mementos.Count) {
return mementos[index];
}
throw new IndexOutOfRangeException("索引超出范围");
}

public int GetMementoCount() {
return mementos.Count;
}
}

// 客户端代码
class Program {
static void Main(string[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();

// 改变状态并保存
originator.SetState("状态1");
caretaker.AddMemento(originator.CreateMemento());

originator.SetState("状态2");
caretaker.AddMemento(originator.CreateMemento());

originator.SetState("状态3");
Console.WriteLine($"当前状态: {originator.GetState()}");

// 恢复到之前的状态
Console.WriteLine("\n恢复到状态1:");
originator.RestoreMemento(caretaker.GetMemento(0));

Console.WriteLine("\n恢复到状态2:");
originator.RestoreMemento(caretaker.GetMemento(1));
}
}

备忘录模式的适用场景

备忘录模式适用于以下情况:

  1. 需要撤销/重做功能:如文本编辑器、图形编辑器等
  2. 需要保存和恢复状态:如游戏存档、应用程序配置等
  3. 需要历史记录:如事务处理、日志系统等
  4. 需要状态回滚:如数据库事务、操作回滚等
  5. 需要保护封装性:在保存和恢复状态的同时,不破坏对象的封装性

实际应用场景

  1. 文本编辑器:保存文档的历史版本,支持撤销和重做
  2. 图形编辑器:保存绘图的历史状态,支持撤销和重做
  3. 游戏:保存游戏进度,支持存档和读档
  4. 配置管理:保存应用程序的配置状态,支持配置回滚
  5. 数据库事务:保存事务的状态,支持提交和回滚
  6. 表单编辑器:保存表单的编辑状态,支持撤销操作

备忘录模式的变体

  1. 增量备忘录:只记录状态的变化,而不是完整状态,减少内存使用
  2. 多状态备忘录:同时保存多个属性的状态
  3. 版本控制:保存对象的多个版本,支持版本切换
  4. 快照模式:定期创建对象的快照,用于恢复

注意事项

  1. 内存使用:如果对象的状态很大,保存多个备忘录可能会占用大量内存
  2. 序列化:如果需要持久化备忘录,需要考虑序列化问题
  3. 线程安全:在多线程环境下,需要考虑线程安全问题
  4. 封装性:确保备忘录的状态不被外部修改
  5. 性能:频繁创建和恢复备忘录可能会影响性能

备忘录模式与其他模式的结合

  1. 命令模式:命令模式可以使用备忘录模式实现撤销功能
  2. 状态模式:状态模式可以使用备忘录模式保存状态
  3. 原型模式:原型模式可以用于创建备忘录的深拷贝

总结

备忘录模式是一种非常实用的设计模式,它通过将对象的状态封装在备忘录中,实现了状态的保存和恢复,同时保护了对象的封装性。备忘录模式不仅可以用于实现撤销和重做功能,还可以用于状态管理、历史记录等场景。

在实际开发中,当需要保存对象的状态以便将来恢复时,备忘录模式是一个很好的解决方案。通过合理的设计,可以在不破坏封装性的前提下,实现灵活的状态管理。