НЕ МОЛЧИ!!!    Сделай что-нибудь, чтобы остановить войну России в Украине.
...бойтесь людей равнодушных - именно с их молчаливого согласия происходят все самые ужасные преступления на свете.   ("Репортаж с петлёй на шее")

Шаблон проектирования Memento(Хранитель)

Рассмотрен поведенческий шаблон проектирования Memento, его назначение, условия применения. Приведен пример реализации шаблона.

Содержание

  • Содержание
  • Применение
  • Итоги

Применение

Шаблон проектирования Memento используется в случаях, когда нужно сохранить состояние объекта с целью восстановления этого состояния. Конечно, можно сохранить состояние объекта считав напрямую значения его свойств. Однако преимущество шаблона Memento в том, что при сохранении снимка объекта знание деталей его реализации клиенту не требуется. Таким образом не нарушается принцип инкапсуляции при разработке приложения. Это обеспечивает простоту модернизации кода объекта, ведь в случае изменения состава или формата его свойств, нам не придется править сторонний код других компонентов ПО, которые напрямую взаимодействуют с объектом.

Реализация

Перед описанием реализации договоримся о терминах. Кроме прочего, это поможет объяснить идею шаблона. В нашем примере будут использоваться Originator(Создатель), Caretaker(Смотритель) и Memento(Хранитель).

  • Originator — Создатель — объект, состояния которого запоминаются и хранятся. По командам создает снимки своего состояния и восстанавливает своё состояние по своим снимкам;
  • Caretaker — Смотритель — дает команды Создателю на создание и восстановление снимков. Замечу, восстановление значения выполняется по принципу LIFO;
  • Memento — Хранитель — объект, хранящий состояние Создателя.

Думаю из описания уже просматривается принцип работы шаблона Memento. Реализован он следующим образом. По команде Смотрителя Создатель создает снимок своих свойств, который запоминается в объекте Хранитель. Если теперь после изменения состояние Создателя, понадобится откатить изменения, Смотритель дает команду Создателю на восстановление. По этой команде Создатель восстанавливает своё предыдущее состояние с помощью объекта Хранитель, передаваемого в команде восстановления.
Вот теперь можно привести код. Начнем с Memento. Его обязанности скромны — сохранить или вернуть переменную.

class Memento 
{
    private $state;

    public function __construct($state) {
        $this->state = $state;
    }

    public function getState() {
        return $this->state;
    }
}

Для простоты кода класс создателя Originator будет иметь лишь одно свойство, состояние которого и будет запоминаться.

class Originator 
{
    private $price;

    public function setPrice($price) {
        $this->price = $price;
        echo "Price updated: " . $this->state);
    }

    public function getPrice() {
        return $this->price;
    }

    public function saveState() {
        return new Memento($this->price);
    }

    public function restoreState(Memento $memento) {
        echo "Restoring state...\n";
        $this->price = $memento->getState();
    }
}

Как приводилось выше класс Caretaker управляет состоянием Создателя. Опять же для упрощения кода свойство $state хранит единственное состояние, а не множество снимков состояния в виде стека.

class Caretaker 
{
    private $state;

    public function getState() {
        return $this->state;
    }

    public function setState(Memento $state) {
        $this->state = $state;
    }
}

Осталось продемонстрировать, как все это взаимодействует.

$originator = new Originator();
$originator->setPrice($25);

// сохраняем состояние
$caretaker = new Caretaker();
$caretaker->setState($originator->saveState());

// изменяем текущее состояние Создателя
$originator->setPrice($30);

// восстанавливаем предыдущее состояние 
$originator->restoreState($caretaker->getState());

Итоги

Главный итог — использование шаблона проектирования Memento позволяет сохранять и восстанавливать состояние объекта наблюдения без знания деталей его внутренней реализации. Это достигается за счет того, что объект наблюдения сам формирует снимок своего состояния по команде извне.
Применение шаблона Memento облегчает доработку программного обеспечения за счет уменьшения взаимосвязей компонентов ПО, позволяет организовать откат изменений объекта без знания его внутренней структуры.