stringtranslate.com

Сувенирный узор

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

Паттерн «память» реализуется с помощью трёх объектов: создателя , смотрителя и сувенира . Создателем является некоторый объект, имеющий внутреннее состояние. Смотритель собирается что-то сделать с инициатором, но хочет иметь возможность отменить изменение. Смотритель сначала просит у создателя памятный предмет. Затем он выполняет любую операцию (или последовательность операций), которую собирался выполнить. Чтобы вернуться к состоянию до выполнения операций, он возвращает объект-память инициатору. Сувенирный объект сам по себе является непрозрачным объектом (который смотритель не может или не должен изменять). При использовании этого шаблона следует проявлять осторожность, если создатель может изменить другие объекты или ресурсы — шаблон «память» работает с одним объектом.

Классические примеры шаблона «память» включают генератор псевдослучайных чисел (каждый потребитель ГПСЧ выступает в роли смотрителя, который может инициализировать ГПСЧ (создатель) с тем же начальным значением (память), чтобы создать идентичную последовательность псевдослучайных чисел) и состояние в конечном автомате.

Обзор

Шаблон проектирования Memento — один из двадцати трех известных шаблонов проектирования GoF , которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторное использование. Шаблон Memento был создан Ноем Томпсоном, Дэвидом Эспириту и доктором Дрю Клинкенбердом для первых продуктов HP.

Какие проблемы может решить шаблон проектирования Memento?

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

Какое решение описывает шаблон проектирования Memento?

Сделать объект (создатель) ответственным за

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

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

Это позволяет сохранить и восстановить внутреннее состояние оригинатора, не нарушая его инкапсуляцию.

См. также класс UML и диаграмму последовательности ниже.

Состав

Класс UML и диаграмма последовательности

Пример класса UML и диаграммы последовательности для шаблона проектирования Memento. [1]

В приведенной выше диаграмме классов UML Caretakerкласс относится к Originatorклассу для сохранения ( createMemento()) и восстановления ( restore(memento)) внутреннего состояния отправителя.
Класс Originatorреализует
(1) createMemento()путем создания и возврата Mementoобъекта, который хранит текущее внутреннее состояние отправителя, и
(2) restore(memento)путем восстановления состояния из переданного Mementoобъекта.

Диаграмма последовательности UML показывает взаимодействия во время выполнения:
(1) Сохранение внутреннего состояния отправителя: Caretakerобъект вызывает createMemento()объект Originator, который создает объект Memento, сохраняет его текущее внутреннее состояние ( setState()) и возвращает Mementoобъект Caretaker.
(2) Восстановление внутреннего состояния отправителя: Caretakerвызывает restore(memento)объект Originatorи указывает Mementoобъект, хранящий состояние, которое необходимо восстановить. Получает Originatorсостояние ( getState()) из для Mementoустановки собственного состояния.

Пример Java

Следующая программа на Java иллюстрирует использование шаблона «память» для «отмены».

импортировать java.util.List ; импортировать java.util.ArrayList ; класс Originator { частное состояние строки ; // Класс также может содержать дополнительные данные, которые не являются частью // состояния, сохраненного в памяти.. public void set ( String state ) { this . состояние = состояние ; Система . вне . println ( "Отправитель: установка состояния в " + состояние "); } Общественный Memento saveToMemento () { System . вне . println ( "Создатель: Сохранение на память." ); вернуть новый Memento ( this.state ) ; _ } Общественность недействительными восстановленияFromMemento ( Memento memento ) { this . состояние = сувенир . ПолучитьСохраненноеСостояние (); Система . вне . println ( "Отправитель: Состояние после восстановления из Memento: " + state ); } Общественный статический класс Memento { частное окончательное состояние строки ;                                                        общественный сувенир ( String stateToSave ) { state = stateToSave ; } // доступно только внешнему классу Private String getSavedState () { return state ; } } } Класс Смотритель { public static void main ( String [] args ) { List < Originator . Memento > saveStates = новый ArrayList < Originator . Напоминание > (); Создатель отправитель = новый отправитель (); создатель . установить ( «Состояние1» ); создатель . установить ( «Состояние2» ); сохраненные состояния . добавить ( оригинатор . saveToMemento ()); создатель . установить ( «Состояние3» ); // Мы можем запросить несколько сувениров и выбрать, к какому из них откатиться. сохраненные состояния . добавить ( оригинатор . saveToMemento ()); создатель . установить ( «Состояние4» ); создатель . RestorFromMemento ( saveStates . get ( 1 )); } }                                                

Результат:

Инициатор: установка состояния в State1Инициатор: установка состояния в State2Создатель: Сохраняю в Memento.Инициатор: установка состояния в State3Создатель: Сохраняю в Memento.Инициатор: установка состояния в State4Оригинатор: Состояние после восстановления из Memento: State3

В этом примере в качестве состояния используется строка, которая является неизменяемым объектом в Java. В реальных сценариях состояние почти всегда будет изменяемым объектом, и в этом случае необходимо сделать копию состояния.

Надо сказать, что показанная реализация имеет недостаток: она объявляет внутренний класс. Было бы лучше, если бы эта стратегия сувениров могла применяться более чем к одному автору.

В основном есть три других способа получить Memento:

  1. Сериализация.
  2. Класс, объявленный в том же пакете.
  3. Доступ к объекту также можно получить через прокси-сервер, который может выполнять любую операцию сохранения/восстановления объекта.

пример С#

Шаблон «память» позволяет фиксировать внутреннее состояние объекта, не нарушая инкапсуляцию, так что позже при необходимости можно отменить/вернуть изменения. Здесь можно видеть, что объект Memento фактически используется для отмены изменений, внесенных в объект.

класс Memento { частная строка saveState, доступная только для чтения ;      частный сувенир ( строка stateToSave ) { savedState = stateToSave ; }        публичный класс Originator { частное состояние строки ; // Класс также может содержать дополнительные данные, которые не являются частью // состояния, сохраненного в сувенире.         public void Set ( состояние строки ) { Console . WriteLine ( "Отправитель: установка состояния в " + состояние "); этот . состояние = состояние ; }            общественный сувенир SaveToMemento () { Console . WriteLine ( "Создатель: Сохранение на память." ); вернуть новый сувенир ( состояние ); }         public void RestoreFromMemento ( Memento memento ) { state = memento . сохраненное состояние ; Консоль . WriteLine ( "Отправитель: Состояние после восстановления из Memento: " + state ); } } }            класс Caretaker { static void Main ( string [] args ) { var saveStates = новый список < Memento > ();            вар создатель = новый сувенир . Создатель (); создатель . Установить ( «Состояние1» ); создатель . Установить ( «Состояние2» ); сохраненные состояния . Добавить ( оригинатор . SaveToMemento ()); создатель . Установить ( "Состояние3" ); // Мы можем запросить несколько сувениров и выбрать, к какому из них откатиться. сохраненные состояния . Добавить ( оригинатор . SaveToMemento ()); создатель . Установить ( "Состояние4" );            создатель . RestoreFromMemento ( saveStates [ 1 ]); } } 

Пример Python

""" Пример шаблона Memento. """ Создатель класса :  _state  =  "" def  set ( self ,  state :  str )  ->  None :  print ( f "Отправитель: установка состояния в { state } " )  self . _state  =  состояние def  save_to_memento ( self )  ->  «Memento» :  вернуть  себя . Сувенир ( self._state ) _ _ def  restre_from_memento ( self ,  m :  «Memento» )  ->  Нет :  self . _state  =  м . get_saved_state ()  print ( f "Отправитель: Состояние после восстановления из Memento: { self . _state } " ) класс  Сувенир : def  __init__ ( self ,  состояние ):  self . _state  =  состояние def  get_saved_state ( self ):  вернуть  себя . _состояниеsave_states  =  [] originator  =  Originator () originator . set ( "State1" ) создатель . set ( "State2" ) save_states . добавить ( составитель . save_to_memento ())создатель . set ( "State3" ) save_states . добавить ( составитель . save_to_memento ())создатель . установить ( «Состояние4» )создатель . restre_from_memento ( сохраненные_состояния [ 1 ])

Пример Javascript

// Паттерн Memento используется для сохранения и восстановления состояния объекта. // Сувенир — это снимок состояния объекта. var Memento = { // Пространство имен: Memento saveState : null , // Сохраненное состояние объекта.        save : function ( state ) { // Сохраняем состояние объекта. этот . saveState = состояние ; },         restore : function () { // Восстанавливаем состояние объекта. верните это . сохраненное состояние ; } };       // Создатель — это объект, создающий сувенир. // определяет метод сохранения состояния внутри сувенира. var Originator = { // Пространство имен: Состояние отправителя : null , // Состояние, которое нужно сохранить        // Создает нового отправителя с начальным состоянием null createMemento : function () { return { state : this . состояние // Состояние копируется в память. }; }, setMemento : function ( memento ) { // Устанавливает состояние отправителя из сувенира this . состояние = сувенир . состояние ; } };                       // Смотритель хранит памятные вещи об объектах и ​​// предоставляет операции для их извлечения. var Caretaker = { // Пространство имен: сувениры смотрителя : [], // Сувениры объектов. addMemento : function ( memento ) { // Добавляем сувенир в коллекцию. этот . сувениры . нажать ( на память ); }, getMemento : function ( index ) { // Получаем сувенир из коллекции. верните это . сувениры [ индекс ]; } };                       вар action_step = "Фу" ; // Действие, которое необходимо выполнить/состояние объекта, которое нужно сохранить. var action_step_2 = "Бар" ; // Действие, которое необходимо выполнить/состояние объекта, которое нужно сохранить.        // устанавливаем исходное состояние Originator . состояние = action_step ; Смотритель . addMemento ( Оригинатор . createMemento ()); // сохраняем состояние в консоли истории . log ( "Исходное состояние :" + Originator.state ) ; // Фу     // меняем состояние Originator . состояние = action_step_2 ; Смотритель . addMemento ( Оригинатор . createMemento ()); // сохраняем состояние в консоли истории . log ( "Состояние после изменения: " + Originator.state ) ; // Бар      // восстанавливаем первое состояние — отменяем Originator . setMemento ( Смотритель . getMemento ( 0 )); консоль . log ( "Состояние после отмены: " + Originator.state ) ; // Фу   // восстанавливаем второе состояние — повторяем Originator . setMemento ( Caretaker.getMemento ( 1 ) ) ; консоль . log ( "Состояние после повтора: " + Originator.state ) ; // Бар   

Рекомендации

  1. ^ «Шаблон проектирования Memento — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.

Внешние ссылки