메멘토 패턴이란

 

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 객체를 위한 메모리를 추가로 사용해야 함

- 구현의 복잡도 증가

 

 

 

 

 

 

※ 참고 문헌

https://bloodstrawberry.tistory.com/1406