// The originator holds some important data that may change over // time. It also defines a method for saving its state inside a // memento and another method for restoring the state from it. classEditor is private field text, curX, curY, selectionWidth
method setText(text) is this.text = text
method setCursor(x, y) is this.curX = x this.curY = y
method setSelectionWidth(width) is this.selectionWidth = width
// Saves the current state inside a memento. method createSnapshot():Snapshot is // Memento is an immutable object; that's why the // originator passes its state to the memento's // constructor parameters. returnnewSnapshot(this, text, curX, curY, selectionWidth)
// The memento class stores the past state of the editor. classSnapshot is private field editor: Editor private field text, curX, curY, selectionWidth
constructor Snapshot(editor, text, curX, curY, selectionWidth) is this.editor = editor this.text = text this.curX = x this.curY = y this.selectionWidth = selectionWidth
// At some point, a previous state of the editor can be // restored using a memento object. method restore() is editor.setText(text) editor.setCursor(curX, curY) editor.setSelectionWidth(selectionWidth)
// A command object can act as a caretaker. In that case, the // command gets a memento just before it changes the // originator's state. When undo is requested, it restores the // originator's state from a memento. classCommand is private field backup: Snapshot
from __future__ import annotations from abc import ABC, abstractmethod from datetime import datetime from random import sample from string import ascii_letters
classOriginator: """ The Originator holds some important state that may change over time. It also defines a method for saving the state inside a memento and another method for restoring the state from it. """
_state = None """ For the sake of simplicity, the originator's state is stored inside a single variable. """
def__init__(self, state: str) -> None: self._state = state print(f"Originator: My initial state is: {self._state}")
defdo_something(self) -> None: """ The Originator's business logic may affect its internal state. Therefore, the client should backup the state before launching methods of the business logic via the save() method. """
print("Originator: I'm doing something important.") self._state = self._generate_random_string(30) print(f"Originator: and my state has changed to: {self._state}")
@staticmethod def_generate_random_string(length: int = 10) -> str: return"".join(sample(ascii_letters, length))
defsave(self) -> Memento: """ Saves the current state inside a memento. """
return ConcreteMemento(self._state)
defrestore(self, memento: Memento) -> None: """ Restores the Originator's state from a memento object. """
self._state = memento.get_state() print(f"Originator: My state has changed to: {self._state}")
classMemento(ABC): """ The Memento interface provides a way to retrieve the memento's metadata, such as creation date or name. However, it doesn't expose the Originator's state. """
defget_state(self) -> str: """ The Originator uses this method when restoring its state. """ return self._state
defget_name(self) -> str: """ The rest of the methods are used by the Caretaker to display metadata. """
returnf"{self._date} / ({self._state[0:9]}...)"
defget_date(self) -> str: return self._date
classCaretaker: """ The Caretaker doesn't depend on the Concrete Memento class. Therefore, it doesn't have access to the originator's state, stored inside the memento. It works with all mementos via the base Memento interface. """
Originator: My initial state is: Super-duper-super-puper-super.
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: wQAehHYOqVSlpEXjyIcgobrxsZUnat
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: lHxNORKcsgMWYnJqoXjVCbQLEIeiSp
Caretaker: Saving Originator's state... Originator: I'm doing something important. Originator: and my state has changed to: cvIYsRilNOtwynaKdEZpDCQkFAXVMf
Caretaker: Here's the list of mementos: 2019-01-26 21:11:24 / (Super-dup...) 2019-01-26 21:11:24 / (wQAehHYOq...) 2019-01-26 21:11:24 / (lHxNORKcs...)
Client: Now, let's rollback!
Caretaker: Restoring state to: 2019-01-26 21:11:24 / (lHxNORKcs...) Originator: My state has changed to: lHxNORKcsgMWYnJqoXjVCbQLEIeiSp
Client: Once more!
Caretaker: Restoring state to: 2019-01-26 21:11:24 / (wQAehHYOq...) Originator: My state has changed to: wQAehHYOqVSlpEXjyIcgobrxsZUnat
/// An object to be stored. It derives a default /// `Serialize` and `Deserialize` trait implementation, which /// allows to convert it into many different formats (e.g. JSON). #[derive(Serialize, Deserialize)] structOriginator { state: u32, }
implOriginator { /// Serializes an originator into a string of JSON format. pubfnsave(&self) ->String { serde_json::to_string(self).unwrap() }
/// Deserializes an originator into a string of JSON format. pubfnrestore(json: &str) ->Self { serde_json::from_str(json).unwrap() } }
fnmain() { // A stack of mementos. letmut history = Vec::<String>::new();