Хранитель (англ.Memento) — поведенческийшаблон проектирования, позволяющий, не нарушая инкапсуляцию, зафиксировать и сохранить внутреннее состояние объекта так, чтобы позднее восстановить его в это состояние.
Существует два возможных варианта реализации данного шаблона: классический, описанный в книге Design Patterns, и реже встречающийся нестандартный вариант.
необходимо сохранить снимок состояния объекта (или его части) для последующего восстановления
прямой интерфейс получения состояния объекта раскрывает детали реализации и нарушает инкапсуляцию объекта
Структура
Классический вариант:
Нестандартный вариант:
Originator — «Создатель»
Caretaker — «Опекун»
Memento — «Хранитель»
Описание
Классический вариант:
Шаблон Хранитель используется двумя объектами: «Создателем» (originator) и «Опекуном» (caretaker). «Создатель» — это объект, у которого есть внутреннее состояние. Объект «Опекун» может производить некоторые действия с «Создателем», но при этом необходимо иметь возможность откатить изменения. Для этого «Опекун» запрашивает у «Создателя» объект «Хранителя». Затем выполняет запланированное действие (или последовательность действий). Для выполнения отката «Создателя» к состоянию, которое предшествовало изменениям, «Опекун» возвращает объект «Хранителя» его «Создателю». «Хранитель» является непрозрачным (то есть таким, который не может или не должен изменяться «Опекуном»).
Нестандартный вариант:
Отличие данного варианта от классического заключено в более жёстком ограничении на доступ «Опекуна» к внутреннему состоянию «Создателя». В классическом варианте у «Опекуна» есть потенциальная возможность получить доступ к внутренним данным «Создателя» через «Хранителя», изменить состояние и установить его обратно «Создателю». В данном варианте «Опекун» обладает возможностью лишь восстановить состояние «Хранителя», вызвав Restore. Кроме всего прочего, «Опекуну» не требуется владеть связью на «Хранителя», чтобы восстановить его состояние. Это позволяет сохранять и восстанавливать состояние сложных иерархических или сетевых структур (состояния объектов и всех связей между ними) путём сбора снимков всех зарегистрированных объектов системы.
classMemento:def__init__(self,state:str):self.__state=statedefget_state(self)->str:returnself.__stateclassCaretaker:def__init__(self,memento:Memento):self.__memento=mementodefget_memento(self)->Memento:returnself.__mementoclassOriginator:def__init__(self,state:str):self.__state=state@propertydefstate(self)->str:returnself.__state@state.setterdefstate(self,state:str)->None:self.__state=statedefsave_state(self)->Memento:returnMemento(self.__state)defrestore_state(self,memento:Memento)->None:self.__state=memento.get_state()if__name__=='__main__':originator=Originator(state='on')print(originator.state)caretaker=Caretaker(originator.save_state())originator.state='off'print(originator.state)originator.restore_state(caretaker.get_memento())print(originator.state)# on# off# on
publicclassMemento{privatefinalStringstate;publicMemento(Stringstate){this.state=state;}publicStringgetState(){returnstate;}}publicclassCaretaker{privateMementomemento;publicMementogetMemento(){returnmemento;}publicvoidsetMemento(Mementomemento){this.memento=memento;}}publicclassOriginator{privateStringstate;publicvoidsetState(Stringstate){this.state=state;}publicStringgetState(){returnstate;}publicMementosaveState(){returnnewMemento(state);}publicvoidrestoreState(Mementomemento){this.state=memento.getState();}}publicclassApplication{publicstaticvoidmain(String[]args){Originatororiginator=newOriginator();Caretakercaretaker=newCaretaker();originator.setState("on");System.out.printf("State is %s\n",originator.getState());caretaker.setMemento(originator.saveState());originator.setState("off");System.out.printf("State is %s\n",originator.getState());originator.restoreState(caretaker.getMemento());System.out.printf("State is %s\n",originator.getState());}}/* * Output: * State is on * State is off * State is on */
<?php/** * Паттерн «Хранитель» хранит и восстанавливает состояния объекта */namespaceMemento{/** * Создатель сохраняет и восстанавливает внутреннее состояние */classOriginator{private$state;publicfunctionsetState($state){$this->state=$state;echosprintf("State setted %s\n",$this->state);}publicfunctiongetState(){return$this->state;}/** * Создать снимок состояния объекта * @return Memento */publicfunctionsaveMemento(){returnnewMemento($this->state);}/** * Восстановить состояние * @param \Memento\Memento $memento */publicfunctionrestoreMemento(Memento$memento){echosprintf("Restoring state...\n");$this->state=$memento->getState();}}/** * Снимок состояния */classMemento{private$state;publicfunction__construct($state){$this->state=$state;}publicfunctiongetState(){return$this->state;}}/** * Смотрящий (опекун) за состоянием объекта */classCaretaker{private$memento;publicfunctiongetMemento(){return$this->memento;}publicfunctionsetMemento(Memento$memento){$this->memento=$memento;}}$originator=newOriginator();$originator->setState("On");// Store internal state$caretaker=newCaretaker();$caretaker->setMemento($originator->saveMemento());// Continue changing originator$originator->setState("Off");// Restore saved state$originator->restoreMemento($caretaker->getMemento());}
usingSystem;usingSystem.Collections.Generic;publicinterfaceIOriginator{IMementoGetState();}publicinterfaceIShape:IOriginator{voidDraw();voidScale(doublescale);voidMove(doubledx,doubledy);}publicinterfaceIMemento{voidRestoreState();}publicclassCircleOriginator:IShape{privateclassCircleMemento:IMemento{privatereadonlydoublex;privatereadonlydoubley;privatereadonlydoubler;privatereadonlyCircleOriginatororiginator;publicCircleMemento(CircleOriginatororiginator){this.originator=originator;x=originator.x;y=originator.y;r=originator.r;}publicvoidRestoreState(){originator.x=x;originator.y=y;originator.r=r;}}doublex;doubley;doubler;publicCircleOriginator(doublex,doubley,doubler){this.x=x;this.y=y;this.r=r;}publicvoidDraw(){Console.WriteLine("Circle with radius {0} at ({1}, {2})",r,x,y);}publicvoidScale(doublescale){r*=scale;}publicvoidMove(doubledx,doubledy){x+=dx;y+=dy;}publicIMementoGetState(){returnnewCircleMemento(this);}}publicclassRectOriginator:IShape{privateclassRectMemento:IMemento{privatereadonlydoublex;privatereadonlydoubley;privatereadonlydoublew;privatereadonlydoubleh;privatereadonlyRectOriginatororiginator;publicRectMemento(RectOriginatororiginator){this.originator=originator;x=originator.x;y=originator.y;w=originator.w;h=originator.h;}publicvoidRestoreState(){originator.x=x;originator.y=y;originator.w=w;originator.h=h;}}doublex;doubley;doublew;doubleh;publicRectOriginator(doublex,doubley,doublew,doubleh){this.x=x;this.y=y;this.w=w;this.h=h;}publicvoidDraw(){Console.WriteLine("Rectangle {0}x{1} at ({2}, {3})",w,h,x,y);}publicvoidScale(doublescale){w*=scale;h*=scale;}publicvoidMove(doubledx,doubledy){x+=dx;y+=dy;}publicIMementoGetState(){returnnewRectMemento(this);}}publicclassCaretaker{publicstaticvoidDraw(IEnumerable<IShape>shapes){foreach(IShapeshapeinshapes){shape.Draw();}}publicstaticvoidMoveAndScale(IEnumerable<IShape>shapes){foreach(IShapeshapeinshapes){shape.Scale(10);shape.Move(3,2);}}publicstaticIEnumerable<IMemento>SaveStates(IEnumerable<IShape>shapes){LinkedList<IMemento>states=newLinkedList<IMemento>();foreach(IShapeshapeinshapes){states.AddLast(shape.GetState());}returnstates;}publicstaticvoidRestoreStates(IEnumerable<IMemento>states){foreach(IMementostateinstates){state.RestoreState();}}publicstaticvoidMain(){IShape[]shapes={newRectOriginator(10,20,3,5),newCircleOriginator(5,2,10)};//Выводит:// Rectangle 3x5 at (10, 20)// Circle with radius 10 at (5, 2)Draw(shapes);//Сохраняем состояния фигурIEnumerable<IMemento>states=SaveStates(shapes);//Изменяем положение фигурMoveAndScale(shapes);//Выводит:// Rectangle 30x50 at (13, 22)// Circle with radius 100 at (8, 4)Draw(shapes);//Восстановление старого положения фигурRestoreStates(states);//Выводит:// Rectangle 3x5 at (10, 20)// Circle with radius 10 at (5, 2)Draw(shapes);}}