-
Memento Pattern(메멘토 패턴)STUDY/디자인패턴 2025. 2. 16. 22:14
메멘토 패턴이란?
객체의 구현 세부 사항을 공개하지 않으면서 해당 객체의 이전 상태를 저장하고 복원할 수 있게 해주는 디자인 행동 패턴
주요 구성 요소
- Originator : 상태를 저장하고 복원하려는 객체
- Memento : 상태를 저장하는 객체
- Caretaker : Memento를 저장하고 관리하는 객체
구조

중첩된 클래스들에 기반한 구현 - Originator
자신의 상태에 대한 스냅샷들을 생성할 수 있으며, 필요시 스냅샷에서 자신의 상태를 복원할 수 있다.
- Memento
오리지네이터의 상태 스냅샷 역할을 하는 값 객체이다.
중첩된 클래스들에 기반한 구현의 경우 메멘토 클래스는 오리지네이터 내부에 중첩된다. 이것은 오리지네이터가 메멘토의 필드들과 메서드들이 비공개로 선언된 경우에도 접근할 수 있도록 한다. 반면에, 케어테이커는 메멘토의 필드들과 메서드들에 매우 제한된 접근 권한을 가지므로 메멘토들을 스택에 저장할 수는 있지만 그들의 상태를 변조할 수는 없다.
- Caretaker
'언제' 그리고 '왜' 오리지네이터의 상태를 캡처해야 하는지 뿐만 아니라 상태가 복원돼야 하는 시기를 알고 있다.
케어테이커는 메멘토들의 스택을 저장하여 오리지네이터의 기록을 추적할 수 있으며, 오리지네이터가 과거로 돌아가야 할 때 맨 위의 메멘토를 스택에서 가져온 후 오리지네이터의 복원 메서드에 전달한다.

중간 인터페이스에 기반한 구현 중첩 클래스들이 없는 경우, 케어테이커들이 명시적으로 선언된 중개 인터페이스를 통해서만 메멘토와 작업할 수 있는 규칙을 만들어 메멘토의 필드들에 대한 접근을 제한할 수 있다. 해당 인터페이스는 메멘토의 메타데이터와 관련된 메서드들만 선언한다.
반면에 오리지네이터들은 메멘토 객체와 직접 작업하여 메멘토 클래스에 선언된 필드들과 메서드들에 접근할 수 있다. 이 접근 방식의 단점은 메멘토의 모든 구성원을 공개로 선언해야 한다는 것이다.

더 엄격한 캡슐화를 사용한 구현 여러 유형의 오리지네이터들과 메멘토들을 보유할 수 있는 방식으로, 각 오리지네이터는 그에 상응하는 메멘토 클래스와 함께 작동한다. 오리지네이터들과 메멘토들은 자신의 상태를 누구에게도 노출하지 않는다.
케어테이커들은 메멘토들에 저장된 상태의 변경에 명시적인 제한을 받는다. 또한 케어테이커 클래스는 복원 메서드가 메멘토 클래스에 정의되어 있으므로 오리지네이터에게서 독립된다.
각 메멘토는 그것을 생성한 오리지네이터와 연결된다. 오리지네이터는 자신의 상태 값들과 함께 자신을 메멘토의 생성자에 전달한다. 이러한 클래스 간의 긴밀한 관계 덕분에 메멘토는 오리지네티어가 적절한 세터들을 정의했을 경우 자신의 오리지네이터의 상태를 복원할 수 있다.
예시

Originator
시간이 지남에 따라 변경될 수 있는 어떤 중요한 데이터를 보유한다. 또한 자신의 상태를 메멘토 내부에 저장하는 메서드와 해당 상태를 메멘토로부터 복원하는 또 다른 메서드를 정의한다.
public class Editor { private String text; private int curX; private int curY; private int selectionWidth; public void setText(String text) { this.text = text; } public void setCursor(int x, int y) { this.curX = x; this.curY = y; } public void setSelectionWidth(int width) { this.selectionWidth = width; } public Snapshot createSnapshot() { return new Snapshot(this, text, curX, curY, selectionWidth); } }Memento
오리지네이터의 이전 상태를 저장하고, 이전 상태를 복원할 수 있는 메서드를 갖는다.
public class Snapshot { private Editor editor; private String text; private int curX; private int curY; private int selectionWidth; public Snapshot(Editor editor, String text, int curX, int curY, int selectionWidth) { this.editor = editor; this.text = text; this.curX = curX; this.curY = curY; this.selectionWidth = selectionWidth; } public void restore() { editor.setText(text); editor.setCursor(curX, curY); editor.setSelectionWidth(selectionWidth); } }Caretaker
public class Command { private Stack<Snapshot> backup = new Stack<>(); public void makeBackup(Editor editor) { backup.push(editor.createSnapshot()); } public void undo() { Snapshot snapshot = backup.pop(); if (snapshot != null) { snapshot.restore(); } } }Client
public class Client { public static void main(String[] args) { Command command = new Command(); Editor editor = new Editor(); editor.setText("state1"); editor.setCursor(1, 1); editor.setSelectionWidth(10); command.makeBackup(editor); editor.setText("state2"); editor.setCursor(2, 2); editor.setSelectionWidth(20); command.makeBackup(editor); editor.setText("state3"); editor.setCursor(3, 3); editor.setSelectionWidth(30); System.out.println("current editor : " + editor.toString()); command.undo(); System.out.println("1 restore editor : " + editor.toString()); command.undo(); System.out.println("2 restore editor : " + editor.toString()); } } ### current editor : Editor{text='state3', curX=3, curY=3, selectionWidth=30} 1 restore editor : Editor{text='state2', curX=2, curY=2, selectionWidth=20} 2 restore editor : Editor{text='state1', curX=1, curY=1, selectionWidth=10}적용
- 객체의 이전 상태를 복원할 수 있도로 객체의 상태 스냅샷들을 생성하려는 경우
- 객체의 field/getter/setter 들에 직접 접근하는 것이 해당 객체의 캡슐화를 위반하는 경우
장단점
장점
- 캡슐화를 위반하지 않고 객체의 상태의 스냅샷들을 생성할 수 있다.
- 케어테이커가 오리지네이터의 상태의 기록을 유지하도록 하여 오리지네이터의 코드를 단순화할 수 있다.
단점
- 클라이언트들이 메멘토들을 너무 자주 생성하면 앱이 많은 RAM을 소모할 수 있다.
- 케어테이커들은 더 이상 쓸모없는 메멘토들을 파괴할 수 있도록 오리지네이터의 수명주기를 추적해야 한다.
- PHP, 파이썬, 자바스크립트와 같은 동적 프로그래밍 언어에서는 메멘토 내의 상태가 그대로 유지된다고 보장할 수 없다.
'STUDY > 디자인패턴' 카테고리의 다른 글
State Pattern(상태 패턴) (0) 2025.02.16 Observer Pattern(옵저버 패턴) (0) 2025.02.16 Mediator Pattern(중재자 패턴) (0) 2025.02.02 Iterator Pattern(반복자 패턴) (0) 2025.02.02 Command Pattern(커맨드 패턴) (0) 2025.01.21