메멘토 패턴이란 |
memento : 기억, 기억의 증표
객체의 내부 상태를 저장하고 나중에 복원할 수 있는 패턴
객체의 상태를 변경하면서 수정할 때 사용
temp 변수의 클래스 버전이라고 보면 되고 git에 commit으로 캡슐만들었다가 revert하듯이
기억 캡슐들을 만들고 관리하는 패턴
메멘토 패턴의 구조 |
1) Originator
- 상태를 가지고 있는 원본 객체
2) Memento
- 순간적으로 상태를 저장하는 객체
- Originator의 상태를 포착하는 temp 변수같은 존재
3) Caretaker
- Memento를 관리하는 객체, Memento의 생성/저장/복원을 담당
메멘토 패턴이 없다면 |
git에 commit하는 상황을 가정하면
class TextEditor
{
private:
string text;
public:
void setText(const string& newText) { text = newText; }
const string& getText() const { return text; }
};
void main()
{
vector<string> git;
TextEditor* editor = new TextEditor();
editor->setText("Hello, world!");
git.push_back(editor->getText());
}
위 상황처럼 vector에 매번 string이 변경될때마다 저장하는 방식으로 구현 가능할 것이다.
메멘토 패턴을 사용한다면 |
Originator가 현재의 상태를 저장하거나, 복원(불러오기)를 할 수 있다.
- 말그대로 텍스트편집기에서 저장하기, 불러오기 누르듯
Memento객체는 다른 이름으로 저장된 파일 내지는 git의 commit 캡슐과 같다.
Caretaker는 Memento들을 관리하는 역할을 맡는다.
#include <iostream>
#include <vector>
using namespace std;
class Memento // memento 객체는 git으로 따지면 하나의 commit 캡슐과 같음
{
private:
string state;
public:
Memento(const string& s) : state(s) {}
const string& getState() const { return state; }
};
/*
TextEditor는 Originator에 해당하는 원본 상태
snapshot으로 memento 객체를 생성해서 그 당시의 상태를 저장
*/
class TextEditor
{
private:
string text;
public:
void setText(const string& newText) { text = newText; }
string getText() const { return text; }
Memento* snapshot() const { return new Memento(text); } // public인것 확인
void restoreMemento(Memento* memento) { text = memento->getState(); }
};
/*
Caretaker는 Memento 객체들을 관리한다.
memento객체들을 addMemento()를 통해 벡터에 보관한다.
getMemento를 이용해 이전 상태를 불러오거나 rollback으로 직전 상태로 되돌릴 수 있다.
*/
class TextEditorCaretaker
{
private:
vector<Memento*> mementos;
public:
void addMemento(Memento* m) { mementos.push_back(m); }
Memento* getMemento(int index) const { return mementos[index]; }
Memento* rollback() {
Memento* ret = mementos.back();
mementos.pop_back();
return ret;
}
};
void main()
{
TextEditor* editor = new TextEditor();
TextEditorCaretaker* caretaker = new TextEditorCaretaker();
editor->setText("Hello, world!");
caretaker->addMemento(editor->snapshot());
editor->setText("I hate c++");
//caretaker->addMemento(editor->createMemento());
editor->setText("My name is ...");
caretaker->addMemento(editor->snapshot());
editor->setText("batsalee!");
caretaker->addMemento(editor->snapshot());
editor->setText("Nice to meet you.");
caretaker->addMemento(editor->snapshot());
/* ---------------------------------------------------- */
editor->restoreMemento(caretaker->getMemento(3));
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->getMemento(2));
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->getMemento(1));
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->getMemento(0));
cout << "Current text: " << editor->getText() << endl;
/* ---------------------------------------------------- */
cout << endl;
editor->restoreMemento(caretaker->rollback());
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->rollback());
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->rollback());
cout << "Current text: " << editor->getText() << endl;
editor->restoreMemento(caretaker->rollback());
cout << "Current text: " << editor->getText() << endl;
}
장단점 |
1) 장점
- 객체의 상태를 저장/복원할 수 있으므로 이전 상태로 쉽게 되돌릴 수 있음
- Memento는 Originator의 상태를 캡슐화해서 기억하므로 Originator의 내부 상태를 숨길 수 있음
- Memento 객체를 이용해 객체의 상태를 효율적으로 관리할 수 있음
2) 단점
- 상태를 저장/복구할때 cost가 많이 들 수 있음
- Memento 객체를 위한 메모리를 추가로 사용해야 함
- 구현의 복잡도 증가
※ 참고 문헌