Инструменты пользователя

Инструменты сайта


php:shablony_proektirovanija:behavioral_patterns:memento

Хранитель (Memento)

▶ code

Шаблон предоставляет возможность восстановить объект в его предыдущем состоянии (отменить действие посредством отката к предыдущему состоянию) или получить доступ к состоянию объекта, не раскрывая его реализацию (т.е. сам объект не обязан иметь функциональность для возврата текущего состояния).

Шаблон Хранитель реализуется тремя объектами: «Смотритель», «Хранитель» и «Хозяин».

Основные недостатки и издержки использования этого шаблона проектирования связаны с объемом объекта «Хозяин». Если он слишком велик, то «Хранитель» должен копировать большой объем информации. Если структура программного продукта подразумевает частое использование шаблона «Хранитель», то требуются значительные системные ресурсы для поддержки производительности программного обеспечения.

Использование:

  • Когда вам нужно сохранять мгновенные снимки состояния объекта (или его части), чтобы впоследствии объект можно было восстановить в том же состоянии.
  • Когда прямое получение состояния объекта раскрывает приватные детали его реализации, нарушая инкапсуляцию.

Преимущества:

  • Не нарушает инкапсуляции исходного объекта.
  • Упрощает структуру исходного объекта. Ему не нужно хранить историю версий своего состояния.

Недостатки:

  • Требует много памяти, если клиенты слишком часто создают снимки.
  • Может повлечь дополнительные издержки памяти, если объекты, хранящие историю, не освобождают ресурсы, занятые устаревшими снимками.
  • В некоторых языках (например, PHP, Python, JavaScript) сложно гарантировать, чтобы только исходный объект имел доступ к состоянию снимка.

Связи с другими паттернами

  • Команду и Снимок можно использовать сообща для реализации отмены операций. В этом случае объекты команд будут отвечать за выполнение действия над объектом, а снимки будут хранить резервную копию состояния этого объекта, сделанную перед самым запуском команды.
  • Снимок можно использовать вместе с Итератором, чтобы сохранить текущее состояние обхода структуры данных и вернуться к нему в будущем, если потребуется.
  • Снимок иногда можно заменить Прототипом, если объект, состояние которого требуется сохранять в истории, довольно простой, не имеет активных ссылок на внешние ресурсы, либо их можно легко восстановить.

Memento.php

<?php
 
// Смотритель. Объект, который знает, почему и когда "Хозяин" должен сохранять и восстанавливать себя.
class Memento
{
    private State $state;
 
    public function __construct(State $state)
    {
        $this->state = $state;
    }
 
    public function getState(): State
    {
        return $this->state;
    }
}
 
// "Хранитель" сохраняет внутреннее состояние объекта "Хозяин".
class  State
{
    public const CREATED = 'created';
    public const PROCESS = 'process';
    public const TEST = 'test';
    public const DONE = 'done';
 
    private string $state;
 
    public function __construct(string $state)
    {
        $this->state = $state;
    }
 
    public function __toString(): string
    {
        return $this->state;
    }
}
 
// Хозяин. Объект, умеющий создавать "Хранителя", а также знающий, как восстановить свое внутреннее состояние из "Хранителя".
class Task
{
    private State $state;
 
    public function getState(): State
    {
        return $this->state;
    }
 
    public function create()
    {
        $this->state = new State(State::CREATED);
    }
 
    public function process()
    {
        $this->state = new State(State::PROCESS);
    }
 
    public function test()
    {
        $this->state = new State(State::TEST);
    }
 
    public function done()
    {
        $this->state = new State(State::DONE);
    }
 
 
    public function saveToMemento(): Memento
    {
        return new Memento($this->state);
    }
 
    public function restoreFromMemento(Memento $memento)
    {
        $this->state = $memento->getState();
    }
}
 
$task = new Task();
$task->create();
 
$memento = $task->saveToMemento();
 
print_r($task->getState() === $memento->getState()); // true
 
$task->test();
print_r($task->getState()); //     [state:State:private] => test
 
$task->restoreFromMemento($memento);
print_r($task->getState()); //     [state:State:private] => created
php/shablony_proektirovanija/behavioral_patterns/memento.txt · Последние изменения: 2023/08/17 23:45 — werwolf