6.1. Memento

  • EN: Memento

  • PL: Pamiątka

  • Type: object

6.1.1. Pattern

  • Undo operation

  • Remembering state of objects

../../_images/designpatterns-memento-pattern.png
```plantuml

class Originator {
    - content: str
    + create_state()
    + restore_state(state)
}

class Memento {
    - content: str
}

class Caretaker {
    - states: list[Memento]
    + push(state)
    + pop()
}

Memento -down[plain]-* Caretaker : composition
Originator -right[dashed]-> Memento : dependency

```

6.1.2. Problem

design-patterns/behavioral/img/designpatterns-memento-problem.png
```plantuml

class Editor {
    - content: str
    + create_state()
    + restore_state(state)
}

class EditorState {
    - content: str
}

class History {
    - states: list[EditorState]
    + push(state)
    + pop()
}

EditorState -down[plain]-* History : composition
Editor -right[dashed]-> EditorState : dependency

```

6.1.3. Solution

../../_images/designpatterns-memento-solution.png

from dataclasses import dataclass, field


@dataclass(frozen=True)
class EditorState:
    content: str


@dataclass
class History:
    states: list[EditorState] = field(default_factory=list)

    def push(self, state: EditorState) -> None:
        self.states.append(state)

    def pop(self) -> EditorState:
        return self.states.pop()


class Editor:
    content: str

    def set_content(self, content: str) -> None:
        self.content = content

    def get_content(self) -> str:
        return self.content

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

    def restore_state(self, state: EditorState):
        self.content = state.content


if __name__ == '__main__':
    editor = Editor()
    history = History()

    editor.set_content('a')
    print(editor.content)
    # a

    editor.set_content('b')
    history.push(editor.create_state())
    print(editor.content)
    # b

    editor.set_content('c')
    print(editor.content)
    # c

    editor.restore_state(history.pop())
    print(editor.content)
    # b

6.1.4. Assignments

Code 6.34. Solution
"""
* Assignment: DesignPatterns Behavioral Memento
* Complexity: medium
* Lines of code: 29 lines
* Time: 13 min

English:
    1. Implement Memento pattern
    2. Create account history of transactions with:
        a. `when: datetime` - date and time of a transaction
        b. `amount: float` - transaction amount
    3. Allow for transaction undo
    4. Run doctests - all must succeed

Polish:
    1. Zaimplementuj wzorzec Memento
    2. Stwórz historię transakcji na koncie z:
        a. `when: datetime` - data i czas transakcji
        b: `amount: float` - kwota transakcji
    3. Pozwól na wycofywanie (undo) transakcji
    4. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> account = Account()

    >>> account.deposit(100.00)
    >>> account.balance
    100.0

    >>> account.deposit(50.00)
    >>> account.balance
    150.0

    >>> account.deposit(25.00)
    >>> account.balance
    175.0

    >>> account.undo()
    >>> account.balance
    150.0
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Final


@dataclass
class Account:
    balance: float = 0.0

    def deposit(self, amount: float) -> None:
        raise NotImplementedError

    def undo(self):
        raise NotImplementedError