{{위키데이터 속성 추적}}
'''메멘토 패턴'''(memento pattern)은 객체를 이전 상태로 되돌릴 수 있는 기능을 제공하는 [[소프트웨어 디자인 패턴]]이다. (롤백을 통한 [[실행 취소]])

메멘토 패턴은 3개의 객체로 구현된다: 오리지네이터(originator), 케어테이커(caretaker), 메멘토(memento). 오리지네이터는 내부 상태를 보유하고 있는 일부 객체이다. 케어테이커는 오리지네이터에 대해 무언가를 하지만 변경에 대한 실행 취소를 하기를 원한다.  케어테이커는 먼저 오리지네이터에게 메멘토 객체를 요청한다. 그 뒤 예정된 일련의 명령을 수행한다. 명령 이전의 상태로 되돌리기 위해 메멘토 객체를 오리지네이터에 반환한다. 메멘토 객체 자신은 [[불투명 자료형]](케어테이커는 변경할 수 없거나 변경해서는 안 되는)이다.

메멘토 패턴의 전형적인 예로 [[유사난수]]의 시드(seed), [[유한 상태 기계]]의 상태(state)를 포함한다.

== 개요 ==
메멘토<ref name="GoF">{{서적 인용|author1=Erich Gamma|author2=Richard Helm|author3=Ralph Johnson|author4=John Vlissides|title=Design Patterns: Elements of Reusable Object-Oriented Software|year=1994|publisher=Addison Wesley|isbn=0-201-63361-2|pages=283ff}}</ref> 디자인 패턴은 유연하고 재사용 가능한 객체 지향 소프트웨어를 설계하기 위해 반복되는 디자인 문제를 해결하는 방법, 즉 객체는 구현, 변경, 테스트, 재사용이 쉬워야 한다는 것을 기술하는, 잘 알려진 23가지 [[디자인 패턴 (책)|GoF 디자인 패턴]]들 중 하나이다. 메멘토 패턴은  초기 HP 제품을 위해 Noah Thompson과 Dr.Drew Clinkenbeard에 의해 제작되었다.

<big>메멘토 디자인 패턴이 해결할 수 있는 문제는 무엇인가?</big><ref>{{웹 인용|url=http://www.w3sdesign.com/|제목=The GoF Design Patterns Memory - Learning Object-Oriented Design & Programming|언어=en|확인날짜=2019-07-23|archive-date=2019-07-29|archive-url=https://web.archive.org/web/20190729221046/http://w3sdesign.com/|url-status=}}</ref>

* 객체의 내부 상태가 외부적으로 저장되어야 이후에 객체가 그 상태를 복구할 수 있다.
* 객체의 캡슐화가 훼손되지 않아야 한다.

문제는 잘 디자인된 객체는 캡슐화되어 있기 때문에 그 표현(데이터 구조)이 내부에 숨겨져 있어 객체의 외부에서 접근할 수 없다는 것이다.

<big>메멘토 디자인 패턴이 설명하는 해결책은 무엇인가?</big>

객체(오리지네이터) 자체가 다음 책임을 갖도록 한다.

* (메멘토) 객체에 그 내부 상태를 저장
* (메멘토) 객체로부터 이전 상태를 복구

메멘토를 생성한 오리지네이터만이 접근이 허용된다.

클라이언트(케어테이커)는 오리지네이터로부터 메멘토를 요청하고(오리지네이터의 내부 상태를 저장하기 위해) 오리지네이터에게 메멘토를 다시 돌려줄 수 있다(이전 상태로 복구하기 위해).

이는 캡슐화를 훼손하지 않고 오리지네이터의 내부 상태를 저장하고 복구할 수 있게해준다.

아래 UML 클래스 및 시퀀스 다이어그램을 함께 보자.

== 구조 ==
=== UML 클래스 및 시퀀스 다이어그램 ===
[[파일:w3sDesign Memento Design Pattern UML.jpg|frame|none|메멘토 디자인 패턴을 위한 샘플 UML 클래스와 시퀀스 다이어그램.<ref>{{웹 인용|title=The Memento design pattern - Structure and Collaboration|url=http://w3sdesign.com/?gr=b06&ugr=struct|website=w3sDesign.com|accessdate=2017-08-12}}</ref>]]위 UML 클래스 다이어그램에서, <code>Caretaker</code> 클래스는 오리지네이터의 내부 상태를 저장(<code>createMemento()</code>)하고 복구(<code>restore(memento)</code>)하기 위해 <code>Originator</code> 클래스를 참조한다.

<code>Originator</code> 클래스는 다음을 구현한다.

(1) 오리지네이터의 현재 내부 상태를 저장하는 <code>Memento</code> 객체를 생성하고 돌려주는 <code>createMemento()</code>

(2) <code>Memento</code> 객체로 전달된 상태를 복구하는 <code>restore(memento)</code>

UML 시퀀스 다이어그램은 런타임 인터렉션을 보여준다.

(1) 오리지네이터의 내부 상태를 저장: <code>Caretaker</code> 객체는, <code>Memento</code> 객체를 생성하고 현재 내부 상태를 저장하고(<code>setState()</code>), <code>Caretaker</code>로 <code>Memento</code>를 돌려주는 <code>Originator</code> 객체의 <code>createMemento()</code>를 호출한다.

(2) 오리지네이터의 내부 상태를 복구: <code>Caretaker</code>는 <code>Originator</code> 객체의 <code>restore(memento)</code>를 호출하고 복구할 상태를 저장하고있는 <code>Memento</code> 객체를 가져온다(<code>getState()</code>).

== 자바 예시 ==
다음 [[자바 (프로그래밍 언어)|자바]] 프로그램은 메멘토 패턴의 "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<Originator.Memento> savedStates = '''new''' ArrayList<Originator.Memento>();

         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])

== 각주 ==
{{각주}}

== 외부 링크 ==
* [http://adapower.com/index.php?Command=Class&ClassID=Patterns&CID=271 Description of Memento Pattern] in [[에이다 (프로그래밍 언어)|Ada]]
* [https://web.archive.org/web/20140724185307/http://www.dofactory.com/Patterns/PatternMemento.aspx Memento UML Class Diagram] with C# and .NET code samples
* [http://sourcemaking.com/design_patterns/memento SourceMaking Tutorial]
* [[wikibooks:Computer_Science_Design_Patterns/Memento#Java_Example|Memento Design Pattern using Java]]

{{디자인 패턴(소프트웨어)}}

[[분류:소프트웨어 디자인 패턴]]