메멘토 memento 패턴 - 타입스크립트 예시
요약
메멘토 memento 패턴을 타입스크립트 코드와 함께 알아봅니다.
메멘토 (Memento) 패턴 요약
패턴 종류 | 핵심 키워드 |
---|---|
메멘토 (Memento) | 객체의 내부 상태를 외부에 노출시키지 않으면서, 객체의 특정 시점 상태를 스냅샷처럼 저장해 두었다가 필요할 때 다시 복원할 수 있게 |

메멘토 (Memento) 패턴
메멘토 패턴은 객체의 내부 상태를 외부에 노출시키지 않으면서, 객체의 특정 시점 상태를 스냅샷처럼 저장해 두었다가 필요할 때 다시 복원할 수 있게 하는 패턴입니다. 이 패턴의 가장 중요한 목표는 캡슐화(Encapsulation)를 유지하는 것입니다.
'게임 저장(Save Game)' 🎮 기능을 생각하면 완벽합니다. 플레이어는 게임의 현재 상태(주인공의 위치, 레벨, 아이템 등)를 저장했다가, 나중에 그 시점부터 다시 시작하고 싶을 때 불러올 수 있습니다. 이때 게임의 복잡한 내부 데이터 구조가 외부에 직접 노출되지 않고, '세이브 파일'이라는 불투명한 객체(메멘토)를 통해 안전하게 상태가 저장되고 복원됩니다.
기본 구조
- Originator: 자신의 상태를 저장하고 복원해야 하는 원본 객체입니다.
save()
메서드를 통해 현재 상태를 담은Memento
객체를 생성하고,restore()
메서드를 통해Memento
객체로부터 자신의 상태를 복원합니다. - Memento:
Originator
의 내부 상태를 저장하는 객체입니다.Originator
만이 메멘토의 모든 데이터에 접근할 수 있어야 하며, 다른 객체들(특히Caretaker
)은 메멘토의 내부를 들여다볼 수 없습니다. - Caretaker:
Memento
객체를 보관하고 관리하는 역할을 합니다. 하지만 메멘토의 내용을 검사하거나 수정하지는 않습니다. 그저Originator
로부터 메멘토를 받아 저장해 두었다가, 나중에Originator
에게 다시 돌려줄 뿐입니다. (예: 실행 취소 내역을 관리하는History
객체)
예시: 간단한 텍스트 편집기 만들기
글을 작성하고, 특정 시점의 내용을 저장(스냅샷)했다가 되돌리는(undo) 간단한 텍스트 편집기를 만들어 보겠습니다.
먼저, 편집기의 상태를 저장할 Memento
클래스를 정의합니다.
// Memento: 편집기의 상태(내용)를 저장
class EditorMemento {
// readonly를 사용하여 외부에서 수정 불가능하도록 함
constructor(public readonly content: string) {}
}
다음으로, 상태를 저장하고 복원할 주체인 Originator
, 즉 Editor
클래스를 만듭니다.
// Originator: 원본 객체
class Editor {
private content: string = "";
write(text: string): void {
this.content += text;
}
getContent(): string {
return this.content;
}
// 현재 상태를 메멘토에 저장
save(): EditorMemento {
console.log("상태 저장: ", this.content);
return new EditorMemento(this.content);
}
// 메멘토로부터 상태를 복원
restore(memento: EditorMemento): void {
this.content = memento.content;
console.log("상태 복원: ", this.content);
}
}
마지막으로, 메멘토들을 관리할 Caretaker
인 History
클래스를 만듭니다.
// Caretaker: 메멘토를 보관하지만 내용은 모름
class History {
private mementos: EditorMemento[] = [];
private editor: Editor;
constructor(editor: Editor) {
this.editor = editor;
}
push(): void {
this.mementos.push(this.editor.save());
}
undo(): void {
// 마지막 상태(현재 상태)를 버리기 위해 pop
this.mementos.pop();
// 그 이전 상태를 가져와 복원
const lastMemento = this.mementos[this.mementos.length - 1];
if (lastMemento) {
this.editor.restore(lastMemento);
} else {
// 스택에 아무것도 없으면 초기 상태로 복원
this.editor.restore(new EditorMemento(""));
}
}
}
// 클라이언트 코드
const editor = new Editor();
const history = new History(editor);
// 1. 첫 번째 문장 작성 및 저장
editor.write("안녕하세요. ");
history.push(); // "안녕하세요. " 상태 저장
// 2. 두 번째 문장 작성 및 저장
editor.write("메멘토 패턴입니다.");
history.push(); // "안녕하세요. 메멘토 패턴입니다." 상태 저장
// 3. 현재 내용 확인
console.log("현재 내용: ", editor.getContent());
// 출력: 현재 내용: 안녕하세요. 메멘토 패턴입니다.
// 4. 실행 취소 (Undo)
history.undo();
console.log("실행 취소 후 내용: ", editor.getContent());
// 출력:
// 상태 복원: 안녕하세요.
// 실행 취소 후 내용: 안녕하세요.
// 5. 한 번 더 실행 취소 (Undo)
history.undo();
console.log("두 번째 실행 취소 후 내용: ", editor.getContent());
// 출력:
// 상태 복원:
// 두 번째 실행 취소 후 내용:
History
객체는 EditorMemento
안에 content
가 있는지조차 모릅니다. 그저 메멘토 객체를 스택에 넣고 빼는 역할만 충실히 수행합니다. 이 덕분에 Editor
의 내부 상태(content
)는 외부로부터 안전하게 보호되면서(캡슐화), 실행 취소와 같은 강력한 상태 관리 기능을 구현할 수 있습니다.
메멘토 패턴 중요 키워드
- 캡슐화를 위반하지 않고 객체의 내부 상태를 외부에 저장합니다.
- 스냅샷과 복원: 특정 시점의 상태를 저장하고, 나중에 그 상태로 되돌릴 수 있습니다.
- 실행 취소(Undo/Redo), 트랜잭션, 상태 저장/불러오기 기능에 매우 유용합니다.
- 역할 분리: 상태를 만드는
Originator
, 상태를 저장하는Memento
, 상태를 관리하는Caretaker
로 역할이 명확히 나뉩니다.
문제 | 객체의 내부 상태를 외부에 노출시키지 않으면서 캡슐화를 위반하지 않고, 객체의 특정 시점 상태를 스냅샷처럼 저장해 두었다가 필요할 때 다시 복원할 수 있게 하는 패턴으로 실행 취소(Undo/Redo) 기능에 매우 유용한 디자인 패턴은? |
보기 | |
답변 | |
정답 | 정답 보기 |