Снимок — это поведенческий паттерн, позволяющий делать снимки внутреннего состояния объектов, а затем восстанавливать их.
При этом Снимок не раскрывает подробностей реализации объектов, и клиент не имеет доступа к защищённой информации объекта.
Сложность:
Популярность:
Применимость: Снимок на Python чаще всего реализуют с помощью сериализации. Но это не единственный, да и не самый эффективный метод сохранения состояния объектов во время выполнения программы.
Концептуальный пример
Этот пример показывает структуру паттерна Снимок , а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.
main.py: Пример структуры паттерна
from __future__ import annotations
from abc import ABC, abstractmethod
from datetime import datetime
from random import sample
from string import ascii_letters
class Originator:
"""
Создатель содержит некоторое важное состояние, которое может со временем
меняться. Он также объявляет метод сохранения состояния внутри снимка и
метод восстановления состояния из него.
"""
_state = None
"""
Для удобства состояние создателя хранится внутри одной переменной.
"""
def __init__(self, state: str) -> None:
self._state = state
print(f"Originator: My initial state is: {self._state}")
def do_something(self) -> None:
"""
Бизнес-логика Создателя может повлиять на его внутреннее состояние.
Поэтому клиент должен выполнить резервное копирование состояния с
помощью метода 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}")
@staticmethod
def _generate_random_string(length: int = 10) -> str:
return "".join(sample(ascii_letters, length))
def save(self) -> Memento:
"""
Сохраняет текущее состояние внутри снимка.
"""
return ConcreteMemento(self._state)
def restore(self, memento: Memento) -> None:
"""
Восстанавливает состояние Создателя из объекта снимка.
"""
self._state = memento.get_state()
print(f"Originator: My state has changed to: {self._state}")
class Memento(ABC):
"""
Интерфейс Снимка предоставляет способ извлечения метаданных снимка, таких
как дата создания или название. Однако он не раскрывает состояние Создателя.
"""
@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:
"""
Создатель использует этот метод, когда восстанавливает своё состояние.
"""
return self._state
def get_name(self) -> str:
"""
Остальные методы используются Опекуном для отображения метаданных.
"""
return f"{self._date} / ({self._state[0:9]}...)"
def get_date(self) -> str:
return self._date
class Caretaker:
"""
Опекун не зависит от класса Конкретного Снимка. Таким образом, он не имеет
доступа к состоянию создателя, хранящемуся внутри снимка. Он работает со
всеми снимками через базовый интерфейс Снимка.
"""
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()
Output.txt: Результат выполнения
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
Снимок на других языках программирования