forked from RefactoringGuru/design-patterns-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
187 lines (137 loc) · 6.45 KB
/
Copy pathmain.py
File metadata and controls
187 lines (137 loc) · 6.45 KB
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
"""
EN: Memento Design Pattern
Intent: Lets you save and restore the previous state of an object without
revealing the details of its implementation.
RU: Паттерн Снимок
Назначение: Фиксирует и восстанавливает внутреннее состояние объекта таким
образом, чтобы в дальнейшем объект можно было восстановить в этом состоянии без
нарушения инкапсуляции.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from datetime import datetime
from random import sample
from string import ascii_letters, digits
class Originator():
"""
EN: 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.
RU: Создатель содержит некоторое важное состояние, которое может со временем
меняться. Он также объявляет метод сохранения состояния внутри снимка и
метод восстановления состояния из него.
"""
_state = None
"""
EN: For the sake of simplicity, the originator's state is stored inside a
single variable.
RU: Для удобства состояние создателя хранится внутри одной переменной.
"""
def __init__(self, state: str) -> None:
self._state = state
print(f"Originator: My initial state is: {self._state}")
def do_something(self) -> None:
"""
EN: 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.
RU: Бизнес-логика Создателя может повлиять на его внутреннее состояние.
Поэтому клиент должен выполнить резервное копирование состояния с
помощью метода save перед запуском методов бизнес-логики.
"""
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}")
def _generate_random_string(self, length: int = 10) -> None:
return "".join(sample(ascii_letters, length))
def save(self) -> Memento:
"""
EN: Saves the current state inside a memento.
RU: Сохраняет текущее состояние внутри снимка.
"""
return ConcreteMemento(self._state)
def restore(self, memento: Memento) -> None:
"""
EN: Restores the Originator's state from a memento object.
RU: Восстанавливает состояние Создателя из объекта снимка.
"""
self._state = memento.get_state()
print(f"Originator: My state has changed to: {self._state}")
class Memento(ABC):
"""
EN: 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.
RU: Интерфейс Снимка предоставляет способ извлечения метаданных снимка,
таких как дата создания или название. Однако он не раскрывает состояние
Создателя.
"""
@abstractmethod
def get_name(self) -> str:
pass
@abstractmethod
def get_date(self) -> str:
pass
class ConcreteMemento(Memento):
def __init__(self, state: str) -> None:
self._state = state
self._date = str(datetime.now())[:19]
def get_state(self) -> str:
"""
EN: The Originator uses this method when restoring its state.
RU: Создатель использует этот метод, когда восстанавливает своё
состояние.
"""
return self._state
def get_name(self) -> str:
"""
EN: The rest of the methods are used by the Caretaker to display
metadata.
RU: Остальные методы используются Опекуном для отображения метаданных.
"""
return f"{self._date} / ({self._state[0:9]}...)"
def get_date(self) -> str:
return self._date
class Caretaker():
"""
EN: 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.
RU: Опекун не зависит от класса Конкретного Снимка. Таким образом, он не
имеет доступа к состоянию создателя, хранящемуся внутри снимка. Он работает
со всеми снимками через базовый интерфейс Снимка.
"""
def __init__(self, originator: Originator) -> None:
self._mementos = []
self._originator = originator
def backup(self) -> None:
print("\nCaretaker: Saving Originator's state...")
self._mementos.append(self._originator.save())
def undo(self) -> None:
if not len(self._mementos):
return
memento = self._mementos.pop()
print(f"Caretaker: Restoring state to: {memento.get_name()}")
try:
self._originator.restore(memento)
except Exception:
self.undo()
def show_history(self) -> None:
print("Caretaker: Here's the list of mementos:")
for memento in self._mementos:
print(memento.get_name())
if __name__ == "__main__":
originator = Originator("Super-duper-super-puper-super.")
caretaker = Caretaker(originator)
caretaker.backup()
originator.do_something()
caretaker.backup()
originator.do_something()
caretaker.backup()
originator.do_something()
print()
caretaker.show_history()
print("\nClient: Now, let's rollback!\n")
caretaker.undo()
print("\nClient: Once more!\n")
caretaker.undo()