概念解析
备忘模式,指的是在不破坏内部结构的前提下捕获一个对象的内部状态,这样便可将该对象恢复到原先的保持状态。备忘模式的最大功能是备份,其主要的三个角色:
- 发起人(Originator):需要进行备份的对象
- 备忘录(Mementor):备份的状态,即一个备份的存档
- 备忘管理者(Caretaker):备份存档的管理者,由它负责与发起人的交互
备忘模式类图如下:
备忘模式的优点:
- 能够恢复之前的状态
- 实现了信息的封装,用户不需要关心状态的保存细节
常用场景:
- 存档/快照场景
- 撤销/恢复功能
- 回滚操作
设计模板
备忘模式的代码框架如下:
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
from copy import deepcopy
class Memento():
"""备忘录"""
def set_attributes(self, dict):
"""深度拷贝字典dict中的所有属性"""
self.__dict__ = deepcopy(dict)
def get_attributes(self):
"""获取属性字典"""
return self.__dict__
class Caretaker():
"""备忘录管理类"""
def __init__(self):
self._mementors = {}
def add_memento(self, name, memento):
# 不同name不同备忘录
self._mementors[name] = memento
def get_memento(self, name):
return self._mementors[name]
class Originator():
"""备份发起人"""
def create_memento(self):
memento = Memento()
memento.set_attributes(self.__dict__)
return memento
def restore_from_memento(self, memento):
self.__dict__.update(memento.get_attributes())
实例分析
场景说明:模拟DOS命令/Linux终端命令下查看历史命令:
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
# 模板中的关键类
from pattern.Memento import Originator, Caretaker, Memento
import logging
class TerminalCmd(Originator):
"""终端命令"""
def __init__(self, text):
self.__cmd_name = ""
self.__cmd_args = []
self.parse_cmd(text)
def parse_cmd(self, text):
"""从字符串中解析命令"""
pass
def get_arguments_from_string(self, str, split_flag):
"""通过split_flag进行分割,获取参数数组"""
pass
def show_cmd(self):
print(self.__cmd_name, self.__cmd_args)
class TerminalCaretaker(Caretaker):
"""终端命令的备忘录管理类"""
def show_history_cmds(self):
"""显示历史命令"""
for key, obj in self._mementors.items():
name = ""
value = []
if obj._TerminalCmd.__cmd_name:
name = obj._TerminalCmd.__cmd_name
if obj._TerminalCmd.__cmd_args:
value = obj._TerminalCmd.__cmd_args
print("第%s条命令:%s %s" % (key, name, value))
def test_terminal():
cmd_idx = 0
caretaker = TerminalCaretaker()
cur_cmd = TerminalCmd("")
while True:
str_cmd = input("请输入指令:")
str_cmd = str_cmd.lower()
if str_cmd.startswith("q"):
exit(0)
elif str_cmd.startswith("h"):
caretaker.show_history_cmds()
# 通过"!"符号表示获取历史的某个指令
elif str_cmd.startswith("!"):
idx = int(str_cmd[1:])
cur_cmd.restore_from_memento(caretaker.get_memento(idx))
cur_cmd.show_cmd()
else:
cur_cmd = TerminalCmd(str_cmd)
cur_cmd.show_cmd()
caretaker.add_memento(cmd_idx, cur_cmd.create_memento())
cmdIdx += 1