文章

设计模式-备忘录模式

应用场景

主要应用在类似于撤销操作的应用场景之中.

假设存在一个文本编辑器, 要对其编辑历史进行记录, 以实现撤销操作

如果使用简单的设计方法, 可以让编辑器包含一个历史记录字段, 用以储存上一次的内容.

classDiagram
    note "只能保存一次历史"
    class Editor{
        +String content
        +String content_history
        +createHistory()
        +restore()
    }

但是问题在于仅能保存一次历史记录. 可以修改成

classDiagram
    note "通过列表保存数据, 可以保存多次"
    class Editor{
        +String content
        +List content_history
        +createHistory()
        +restore()
    }

虽然可以保存多次了, 但是本质上来说, 历史记录并不是Editor应该要关心的事.

也就是违反了SRP(Single Responsibility Principle)原则.

使用备忘录模式(memento pattern)的方案大致如下:

classDiagram
    Editor ..> EditorState
    History o-- EditorState
    class Editor{
        + String content
        + createState()
        + restore(state)
    }

    class History{
        + List states
        + push(state)
        + pop()
    }

    class EditorState{
        + content:String
    }
  • Editor 仅负责处理当前编辑的内容;
  • History 只进行历史数据管理;
  • EditorState 仅保存单词的历史信息

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
from collections import namedtuple

EditorState = namedtuple('EditorState', ['title', 'content'])


class History:

    __history = []

    def push(self, record: EditorState):
        self.__history.append(record)

    def pop(self):
        return self.__history.pop()


class Editor:

    def __init__(self, title=None, content=None):
        self.__title = title
        self.__content = content

    @property
    def title(self):
        return self.__title

    @title.setter
    def title(self, value):
        self.__title = value

    @property
    def content(self):
        return self.__content

    @content.setter
    def content(self, value):
        self.__content = value

    def restore(self, state: EditorState):
        self.title = state.title
        self.content = state.content

    def create_state(self):
        return EditorState(self.title, self.content)

    def __str__(self):
        return f"{self.title}:{self.content}"


if __name__ == "__main__":

    editor = Editor()
    history = History()

    editor.title = "title 1"
    editor.content = "content of editor 1"
    history.push(editor.create_state())
    print(editor)   # title 1:content of editor 1

    editor.title = "title 2"
    editor.content = "content of editor 2"
    history.push(editor.create_state())
    print(editor)   # title 2:content of editor 2

    editor.title = "title 3"
    editor.content = "content of editor 3"
    print(editor)   # title 3:content of editor 3

    editor.restore(history.pop())
    print(editor)   # title 2:content of editor 2
本文由作者按照 CC BY 4.0 进行授权