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

Я не буду рассказывать что такое шаблоны проектирования (design patterns), что такое GoF и т.д. Сразу перейду к одному из поведенческих шаблонов — Хранитель.

В чем суть шаблона — позволяет сохранить состояние объекта с последующей возможностью восстановления.

Сразу перейдем от слов к делу. Рассмотрим простой код:

Здесь у нас простой класс с 2 полями. Единственное что нам интересно, так это 2 метода — save и restore. Метод сохранения создает и возвращает новый экземпляр класса Memento, а метод restore восстанавливает данные из объекта такого же класса. Грубо говоря мы переложили данные из нашего класса в некий контейнер и вернули из этого контейнера.

Рассмотрим сам контейнер — класс Хранитель:

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

Теперь же давайте посмотрим простой пример как это все работает:

Сначала мы создаем экземпляр нашего класса с начальными данными 0 и «initial», после этого сохраняем начальное состояние в экземпляре хранителя, после чего меняем значения у исходного класса и восстанавливаем из сохраненного объекта, проверяем поля — юнит-тест проходит.

А теперь рассмотрим плюсы и минусы этого шаблона

Плюсы:
— можно сохранять несколько состояний и восстанавливать их по выбору

Минусы:
— в точности приходится копировать (и раскрывать) структуру объекта,
— лишний (на мой взгляд) класс для простого сохранения и восстанавления (альтернатива с моей стороны ниже)
— при любых изменениях в основном классе придется менять и класс хранителя
(также в оригинале используется еще класс-обертка над хранителем — так называемый опекун, который имеет инстанс хранителя, геттер и сеттер)

Альтернатива

Итак, если наш класс хранитель полностью копирует структуру класса, то почему бы не исползовать сам класс? Например так

Единственное отличие от первой версии в том, что в методах сохранения и восстановления используется тот же класс, а не другой.

Проверим на точно таком же тесте, заменив класс хранителя на класс источника:

Хотя в этом случае получается вся логика лежит в одном классе и бытует мнение что это не хорошо. Давайте тогда рассмотрим еще одну альтернативу.

Альтернатива 2

Давайте оставим в классе источника только 1 метод копирования из другого экземпляра.

И будем использовать его как для сохранения состояния так и для восстановления.

Класс хранителя будет выглядеть примерно так

Обычный класс-обертка над источником, где сохраняется объект и восстанавлиается посредством геттера. В итоге класс хранителя никак не копирует и не показывает внутреннюю структуру источника.

Посмотрим как это все работает

Заметим, что инстанс не подменяется, перезаписываются лишь поля объекта.

Запись опубликована в рубрике Программирование Java. Добавьте в закладки постоянную ссылку.