1. 简介
备忘录模式(Memento Pattern)是一种行为型设计模式,它将对象的状态快照的创建工作委派给实际状态的拥有者原发器(Originator)对象。另一方面,备忘录模式建议将对象状态的副本存储在一个名为备忘录(Memento)的特殊对象中。
2. 模式结构
classDiagram
class Client {
+main()
}
class Memento {
-state: Any
+getState(): Any
}
class Originator {
-state: Any
+operate()
}
class Caretaker {
-originator: Originator
-undoStack: List[Memento]
-redoStack: List[Memento]
+save()
+undo()
+redo()
}
Caretaker o-- Memento
Originator ..> Memento
Client ..> Originator
Client ..> Caretaker
- 原发器 (Originator) 类可以生成自身状态的快照, 也可以在需要时通过快照恢复自身状态。
- 备忘录 (Memento) 是原发器状态快照的值对象 (value object)。 通常做法是将备忘录设为不可变的, 并通过构造函数一次性传递数据。
- 负责人 (Caretaker) 仅知道 “何时” 和 “为何” 捕捉原发器的状态, 以及何时恢复状态。
3. 使用场景以及优缺点
应用场景:
- 需要提供撤销操作的功能。
- 需要保存和恢复特定状态,但不希望暴露对象的内部实现。
优点:
- 封装性:备忘录模式通过将状态的保存和恢复封装在不同的对象中,提高了系统的封装性。
- 安全性:Originator的内部状态可以被保存而无需暴露给其他对象。
- 可扩展性:可以容易地添加更多的状态或撤销级别。
缺点:
- 资源消耗:如果保存的状态信息过多,可能会消耗大量的内存。
- 复杂性:增加了系统的复杂性,因为需要额外的类和对象来实现备忘录模式。
4. 练习:【设计模式专题之备忘录模式】17-redo计数器应用
"""
【设计模式专题之备忘录模式】17-redo计数器应用
时间限制:1.000S 空间限制:256MB
题目描述
小明正在设计一个简单的计数器应用,支持增加(Increment)和减少(Decrement)操作,以及撤销(Undo)和重做(Redo)操作,请你使用备忘录模式帮他实现。
输入描述
输入包含若干行,每行包含一个字符串,表示计数器应用的操作,操作包括 "Increment"、"Decrement"、"Undo" 和 "Redo"。
输出描述
对于每个 "Increment" 和 "Decrement" 操作,输出当前计数器的值,计数器数值从0开始 对于每个 "Undo" 操作,输出撤销后的计数器值。 对于每个 "Redo" 操作,输出重做后的计数器值。
输入示例
Increment
Increment
Decrement
Undo
Redo
Increment
输出示例
1
2
1
2
1
2
"""
from typing import List
class Memento:
def __init__(self, state: int):
self._state = state
@property
def state(self) -> int:
return self._state
class Counter:
""" 充当备忘录模式的Originator """
def __init__(self):
self._value = 0
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, v: int):
self._value = v
def increment(self) -> Memento:
mem = Memento(self._value)
self._value += 1
return mem
def decrement(self) -> Memento:
mem = Memento(self._value)
self._value -= 1
return mem
class MemorableCounter:
""" 充当备忘录模式的Caretaker """
def __init__(self, counter: Counter):
self._counter = counter
self.undoStack: List[Memento] = []
self.redoStack: List[Memento] = []
def increment(self):
self.redoStack.clear() # 像VSCode这类编辑器的Redo功能貌似都是这样做的
mem = self._counter.increment()
self.undoStack.append(mem)
print(self._counter.value)
def decrement(self):
self.redoStack.clear()
mem = self._counter.decrement()
self.undoStack.append(mem)
print(self._counter.value)
def undo(self):
if not self.undoStack:
return
current = Memento(self._counter.value)
self.redoStack.append(current)
last = self.undoStack.pop()
self._counter.value = last.state
print(self._counter.value)
def redo(self):
if not self.redoStack:
return
current = Memento(self._counter.value)
self.undoStack.append(current)
last = self.redoStack.pop()
self._counter.value = last.state
print(self._counter.value)
def client():
counter = Counter()
caretaker = MemorableCounter(counter)
while True:
try:
operation = input()
except EOFError:
break
else:
if operation == "Increment":
caretaker.increment()
if operation == "Decrement":
caretaker.decrement()
if operation == "Undo":
caretaker.undo()
if operation == "Redo":
caretaker.redo()
if __name__ == "__main__":
client()