Паттерн проектирования — это продуманный способ построения исходного кода программы для решения часто возникающих в повседневном программировании проблем проектирования. Иными словами, это уже придуманное решения, для типичной задачи. При этом паттерн не готовое решение, а просто алгоритм действий, который должен привести к желаемому результату. Давайте рассмотрим один из наиболее часто используемых поведенческих паттернов — Хранитель (Memento).

Как я уже писал ранее, существует три вида паттернов проектирования:

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

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

Давайте рассмотрим диаграмму паттерна Хранитель

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

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

  • Originator — основной объект. Именно его состояние будет сохраняться и восстанавливаться
  • Memento — снимок состояния основного объекта. Хранит в тебе все важные данные
  • Carataker — хранилище снимков, позволяет сохранять и восстанавливать любое из хранимых состояний.

Давайте рассмотрим основную логику работы паттерна Хранитель. Если у нас есть объект, который с которым ведется основное взаимодействие и нам нужно сохранить его состояние, но при этом мы не хотим делать его полную копию, так как в некоторых случаях это может раскрыть его внутреннюю структуру или предоставить доступ к свойствам и методам нежелательным пользователям, то мы можем создать уменьшенную копию объекта только с теми данными, которые хотим сохранить. Это позволит не только защитится от нежелательного доступа и соблюсти инкапсуляцию, но и также экономит ресурсы при хранении больших объемов данных. Первое, что приходит в голову при рассмотрении данного паттерна, это конечно же сохранение в компьютерных играх. Вспомним другую статью, где я уже использовал близкую предметную область. Это была статья Паттерн проектирования Абстрактная фабрика (Abstract Factory) на C#. В ней рассматривались космические корабли, позволяющие соревноваться в скорости и в битве. Переработаем данную предметную область и реализуем сохранение состояние космического корабля перед боем с возможностью загрузиться.

Реализация

Для начала реализуем класс космического корабля. В нем мы реализуем необходимые свойства и методы для работы корабля, а так же методы сохранения состояния и восстановления состояния из снимка. Обратите внимание, что мы не раскрываем внутреннюю структуру класса, так как именно внутри класса определяем логику сохранения и загрузки. Поэтому я специально добавил свойство RandomValue, которое не попадает в снимок, чтобы показать что класс сам контролирует какие свойства являются для него важными. Так же взаимодействие с классом MementoSpaceship осуществляется с через набор параметров-свойств, а не целым объектом класса Spaceship. Если бы в MementoSpaceship передавался экземпляр класса Spaceship, то было бы чрезмерное раскрытие внутренней структуры класса, снимок получил бы доступ ко всем свойствам и даже методам класса, и мог бы внести какие-либо изменения. В данном случае же мы от этого застрахованы. Это позволяет лучше придерживаться принципа инкапсуляции.

Так же реализуем класс контроллер для выполнения сражений между кораблями.

Теперь создадим класс хранитель. В нем нужно указать все поля, которые должны быть сохранены, и при необходимости добавить вспомогательные, как например дата создания снимка.

Ну и наконец добавим класс для хранения снимков. Он позволяет добавлять снимок в коллекцию всех состояний, а так же получать последний снимок. При необходимости можно реализовывать дополнительную логику работы, например получение конкретного снимка.

Теперь нам остается только реализовать взаимодействие с пользователем и поработать со снимками.

В итоге получаем следующий результат.

Исходный код доступен в репозитории github.

P.S. Присоединяйся в любой удобной для тебя социальной сети. Для меня очень важно оставаться с тобой на связи, ведь у меня есть еще много полезной информации о программировании для тебя, которой я хочу с тобой поделиться.

Вконтакте
Telegram
Facebook
Twitter
Одноклассники
Дзен
Google+
 
×
%d такие блоггеры, как: