메멘토 패턴

**메멘토 패턴**(memento pattern)은 객체를 이전 상태로 되돌릴 수 있는 기능을 제공하는 소프트웨어 디자인 패턴이다. (롤백을 통한 실행 취소) 메멘토 패턴은 3개의 객체로 구현된다: 오리지네이터(originator), 케어테이커(caretaker), 메멘토(memento). 오리지네이터는 내부 상태를 보유하고 있는 일부 객체이다. 케어테이커는 오리지네이터에 대해 무언가를 하지만 변경에 대한 실행 취소를 하기를 원한다. 케어테이커는 먼저 오리지네이터에게 메멘토 객체를 요청한다. 그 뒤 예정된 일련의 명령을 수행한다. 명령 이전의 상태로 되돌리기 위해 메멘토 객체를 오리지네이터에 반환한다. 메멘토 객체 자신은 불투명 자료형(케어테이커는 변경할 수 없거나 변경해서는 안 되는)이다. 메멘토 패턴의 전형적인 예로 유사난수의 시드(seed), 유한 상태 기계의 상태(state)를 포함한다.
# 개요
메멘토pages=283ff 디자인 패턴은 유연하고 재사용 가능한 객체 지향 소프트웨어를 설계하기 위해 반복되는 디자인 문제를 해결하는 방법, 즉 객체는 구현, 변경, 테스트, 재사용이 쉬워야 한다는 것을 기술하는, 잘 알려진 23가지 GoF 디자인 패턴들 중 하나이다. 메멘토 패턴은 초기 HP 제품을 위해 Noah Thompson과 Dr.Drew Clinkenbeard에 의해 제작되었다. 메멘토 디자인 패턴이 해결할 수 있는 문제는 무엇인가?url-status= * 객체의 내부 상태가 외부적으로 저장되어야 이후에 객체가 그 상태를 복구할 수 있다. * 객체의 캡슐화가 훼손되지 않아야 한다. 문제는 잘 디자인된 객체는 캡슐화되어 있기 때문에 그 표현(데이터 구조)이 내부에 숨겨져 있어 객체의 외부에서 접근할 수 없다는 것이다. 메멘토 디자인 패턴이 설명하는 해결책은 무엇인가? 객체(오리지네이터) 자체가 다음 책임을 갖도록 한다. * (메멘토) 객체에 그 내부 상태를 저장 * (메멘토) 객체로부터 이전 상태를 복구 메멘토를 생성한 오리지네이터만이 접근이 허용된다. 클라이언트(케어테이커)는 오리지네이터로부터 메멘토를 요청하고(오리지네이터의 내부 상태를 저장하기 위해) 오리지네이터에게 메멘토를 다시 돌려줄 수 있다(이전 상태로 복구하기 위해). 이는 캡슐화를 훼손하지 않고 오리지네이터의 내부 상태를 저장하고 복구할 수 있게해준다. 아래 UML 클래스 및 시퀀스 다이어그램을 함께 보자.
# 구조

## UML 클래스 및 시퀀스 다이어그램
accessdate=2017-08-12위 UML 클래스 다이어그램에서, `Caretaker` 클래스는 오리지네이터의 내부 상태를 저장(`createMemento()`)하고 복구(`restore(memento)`)하기 위해 `Originator` 클래스를 참조한다. `Originator` 클래스는 다음을 구현한다. (1) 오리지네이터의 현재 내부 상태를 저장하는 `Memento` 객체를 생성하고 돌려주는 `createMemento()` (2) `Memento` 객체로 전달된 상태를 복구하는 `restore(memento)` UML 시퀀스 다이어그램은 런타임 인터렉션을 보여준다. (1) 오리지네이터의 내부 상태를 저장: `Caretaker` 객체는, `Memento` 객체를 생성하고 현재 내부 상태를 저장하고(`setState()`), `Caretaker`로 `Memento`를 돌려주는 `Originator` 객체의 `createMemento()`를 호출한다. (2) 오리지네이터의 내부 상태를 복구: `Caretaker`는 `Originator` 객체의 `restore(memento)`를 호출하고 복구할 상태를 저장하고있는 `Memento` 객체를 가져온다(`getState()`).
# 자바 예시
다음 자바 프로그램은 메멘토 패턴의 "undo" 사용을 보여준다. **import** **java.util.List**; **import** **java.util.ArrayList**; **class** **Originator** { **private** String state; *// The class could also contain additional data that is not part of the* *// state saved in the memento..* **public** void set(String state) { **this**.state = state; System.out.println("Originator: Setting state to " + state); } **public** Memento saveToMemento() { System.out.println("Originator: Saving to Memento."); **return** **new** Memento(**this**.state); } **public** void restoreFromMemento(Memento memento) { **this**.state = memento.getSavedState(); System.out.println("Originator: State after restoring from Memento: " + state); } **public** **static** **class** **Memento** { **private** **final** String state; **public** Memento(String stateToSave) { state = stateToSave; } *// accessible by outer class only* **private** String getSavedState() { **return** state; } } } **class** **Caretaker** { **public** **static** void main(String[] args) { List savedStates = **new** ArrayList(); Originator originator = **new** Originator(); originator.set("State1"); originator.set("State2"); savedStates.add(originator.saveToMemento()); originator.set("State3"); *// We can request multiple mementos, and choose which one to roll back to.* savedStates.add(originator.saveToMemento()); originator.set("State4"); originator.restoreFromMemento(savedStates.get(1)); } } 출력은 다음과 같다. Originator: Setting state to State1 Originator: Setting state to State2 Originator: Saving to Memento. Originator: Setting state to State3 Originator: Saving to Memento. Originator: Setting state to State4 Originator: State after restoring from Memento: State3 This example uses a String as the state, which is an immutable object in Java. In real-life scenarios the state will almost always be an object, in which case a copy of the state must be done. 이 예시에서는 Java에서 불변한 객체인 String을 상태로써 사용한다. 실제 시나리오에서는 상태가 거의 항상 객체일 것이며, 상태의 복사가 반드시 이루어져야 한다. 내부 클래스를 선언한것에 대해 구현이 취약점을 보인다고 말할 수 있을 것이다. 이 메멘토 전략은 오리지네이터가 하나 이상일 때 적용한다면 더 나을 것이다. 메멘토를 달성하는 다른 세 가지 주요 방법은 다음과 같다. # 직렬화. # 동일한 패키지에 선언된 클래스. # 객체에 저장/복구 작업을 할 수 있는 프록시를 통해 접근할 수도 있는 객체.
# C# 예시
메멘토 패턴은 캡슐화를 훼손하지 않고 객체의 내부 상태를 캡쳐할 수 있게 해주므로 이후에 필요한 경우 변경사항을 되돌리거나 취소할 수 있다. 다음 코드에서는 객체에서 발생한 변경사항을 취소하기 위해 *메멘토 객체*가 실제로 사용되는 것을 볼 수 있다. 1 **public** **class** **OriginalObject** 2 { 3 **public** string String1 { **get**; **set**; } 4 **public** string String2 { **get**; **set**; } 5 6 **public** OriginalObject(string str1, string str2) 7 { 8 **this**.String1 = str1; 9 **this**.String2 = str2; 10 } 11 12 **public** **void** SetMemento(Memento memento) 13 { 14 **this**.String1 = memento.string1; 15 **this**.String2 = memento.string2; 16 } 17 18 **public** Memento CreateMemento() 19 { 20 **return** **new** Memento(**this**.String1, **this**.String2); 21 } 22 } 23 24 *//Memento object* 25 **public** **class** **Memento** 26 { 27 **public** **readonly** string string1; 28 **public** **readonly** string string2; 29 30 **public** Memento(string str1, string str2) 31 { 32 **this**.string1 = str1; 33 **this**.string2 = str2; 34 } 35 } 36 37 *//CareTaker Object* 38 **public** **class** **CareTaker** 39 { 40 **public** Memento Memento { **get**; **set**; } 41 } 42 43 *//Client* 44 **class** **Program** 45 { 46 **static** **void** Main(string[] args) 47 { 48 *// Create Originator object which container first state of "First" and "One".* 49 *// The Memento will remember these value.* 50 OriginalObject original = **new** OriginalObject("First", "One"); 51 52 *// Create first State and store to caretaker* 53 Memento firstMemento = original.CreateMemento(); 54 CareTaker caretaker = **new** CareTaker(); 55 caretaker.Memento = firstMemento; 56 57 *// Change into second state; "Second" and "Two".* 58 original.String1 = "Second"; 59 original.String2 = "Two"; 60 61 *// Retrieve back first State* 62 original.SetMemento(caretaker.Memento); 63 64 } 65 }
# Python 예시
*"""* *Memento pattern example.* *"""* **class** **Memento**(object): **def** __init__(self, state): self._state = state **def** get_saved_state(self): **return** self._state **class** **Originator**(object): _state = "" **def** set(self, state): **print**("Originator: Setting state to", state) self._state = state **def** save_to_memento(self): **print**("Originator: Saving to Memento.") **return** Memento(self._state) **def** restore_from_memento(self, memento): self._state = memento.get_saved_state() **print**("Originator: State after restoring from Memento:", self._state) saved_states = [] originator = Originator() originator.set("State1") originator.set("State2") saved_states.append(originator.save_to_memento()) originator.set("State3") saved_states.append(originator.save_to_memento()) originator.set("State4") originator.restore_from_memento(saved_states[0])