# 설명
메멘토(Memento)는 기억의 증표라는 뜻을가지고 있다. 즉 메멘토 패턴을 이용해서 한순간의 기억을 저장(snapshot)했다가 복구(restore)할 수 있다.
복사한 인스턴스를 바꿔주는 것이 아닌, 인스턴스의 상태를 메멘토(Memento)로써 기억하게 한다. 인스턴스를 복원하려면 내부 정보에 자유롭게 접근해야하지만, 그렇게 되면 캡슐화의 원칙이 깨질 위험이 있다. 오직 메멘토로 하여금 이러한 복원작업을 할 수 있게 보증해야한다.
- Originator : 우리가 사용하고 있는 현재 상태의 객체이다. save와 restore와 같은 기능을 Memento를 통해서 수행하며 state의 상태가 이에 따라서 바뀐다. Originator의 state의 은닉을 유지하고, 상태를 저장 복구 할 수 있다.
- Memento : Originator 객체의 내부 State에서 필요한 State를 저장한다.
- CareTaker : Memento의 보관을 책임진다.
복잡한 Originator 클래스의 내부 상태를 다른 객체(Memento)로 분리함으로써 상태에 대한 캡슐화를 보장할 수 있고 복구에 필요한 (클라이언트가 요구하는) 상태만 따로 관리함으로써, Originator 내부에서 저장하지 않고 Originator가 단순해질수 있다.
# 예제
- GOF의 유명한 예제인 주사위(DICE)예제를 살펴보겠다.
- Gamer클래스를 통해서 게임을 시작하고 원하는 횟수만큼 bet을 수행한다.
- bet을 통해 주사위가 던져지면 특정수가 나오면 money가 두배가 되며, 특정수가 나오면 money가 반토막(/2)이 된다.
- Gamer는 money와 Fruits를 가지고 있다. 또한 메멘토를 통해서 해당 State의 undo, restore기능을 제공한다.
- 클라이언트에서 게임이 시작되고, 메멘토보다 money가 작아지면 그 전 상태로 복구, memento보다 돈이 많아지면 memento에 현재 상태를 복사한다.
# 코드
## Gamer
public class Gamer {
private int money;
private ArrayList<String> fruits = new ArrayList();
private Random random = new Random();
private static String[] fruitNames = {
"사과", "포도", "바나나", "귤",
};
public Gamer(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
// 베팅...게임 진행한다.
public void bet() {
// 주사위를 던진다.
int dice = random.nextInt(6) + 1;
if (dice == 1) {
// 1인 경우, 소지금 증가한다.
money += 100;
System.out.println("소지금이 증가하였습니다.");
} else if (dice == 2) {
// 2인 경우, 소지금이 절반이 된다.
money /= 2;
System.out.println("소지금이 절반이 되었습니다.");
} else if (dice == 6) {
// 6인 경우, 과일을 받는다.
String fruit = getFruit();
System.out.println("과일(" + fruit + ")을 받았습니다.");
fruits.add(fruit);
} else {
// 그외인 경우, 아무 일도 일어나지 않는다.
System.out.println("아무 일도 일어나지 않았다.");
}
}
// 스냅샷 생성: 현재 상황을 저장한 객체를 생성하고 반환한다.
public Memento createMemento() {
Memento memento = new Memento(this.money);
for( String fruit : fruits) {
if(fruit.startsWith("맛있는")){
memento.addFruit(fruit);
}
}
return memento;
}
// 실행 취소(Undo)을 실행: 저장했던 객체를 전달받아 이전 상태로 되돌린다.
public void restoreMemento(Memento memento) {
this.money = memento.getMoney();
this.fruits = memento.getFruits();
}
public String toString() {
return "[money = " + money + ", fruits = " + fruits + "]";
}
private String getFruit() {
String prefix = "";
if (random.nextBoolean()) {
prefix = "맛있는 ";
}
return prefix + fruitNames[random.nextInt(fruitNames.length)];
}
}
## Memento
public class Memento {
private int money;
private ArrayList<String> fruits;
Memento(int money){
this.money = money;
fruits = new ArrayList<String>();
}
int getMoney(){
return money;
}
void addFruit(String fruit) {
fruits.add(fruit);
}
ArrayList<String> getFruits() {
return (ArrayList<String>) fruits.clone();
}
}
## Client
public class Client {
public static void main(String[] args) {
// 첫 소지금은 100이다.
Gamer gamer = new Gamer(100);
// 첫번째 상태를 저장한다.
Memento memento = gamer.createMemento();
ArrayList<Memento> careTaker = new ArrayList<Memento>();
// 초기 상태를 careTaker에 등록해놓습니다.
careTaker.add(memento);
for (int i = 0; i < 10; i++) {
System.out.println("==== " + i);
System.out.println("현재 상태:" + gamer);
// 게임을 진행한다.
gamer.bet();
System.out.println("소지금은 " + gamer.getMoney() + "원이 되었습니다.");
if( gamer.getMoney() < memento.getMoney() /2 ){
System.out.println(" ( 파산을 막기위해 이전 상태로 복구합니다. ) ");
gamer.restoreMemento(memento);
}else if ( gamer.getMoney() >= memento.getMoney()){
System.out.println(" ( 돈이 많아서 현재 상태를 SAVE 합니다. ) ");
memento = gamer.createMemento();
careTaker.add(memento);
}
// 천천히 플레이 될 수 있도록
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
System.out.println("");
}
System.out.println();
System.out.println("memento 상황 조회");
for( Memento m : careTaker) {
System.out.println(m.getMoney());
}
}
}
# 실행 결과
# 참고
Design Pattern | Memento Pattern (메멘토 패턴)
Memento 패턴이란? Memento 라는 영어 단어는 기념품, 모양, 추억의 종이라는 의미이다. 객체 지향 프로그램에서의 실행 취소(Undo)를 하려면, 인스턴스가 가지고 있는 정보를 저장해야 한다. 인스턴스
www.devkuma.com
'• 독서 > Design Pattern' 카테고리의 다른 글
[디자인패턴] 중재자 패턴(Mediator Pattern) (0) | 2022.10.11 |
---|---|
[디자인패턴] 퍼사드 패턴(Facade Pattern) (0) | 2022.10.11 |
[디자인 패턴] 옵저버 패턴(Observer Pattern) (1) | 2022.10.04 |
[디자인 패턴] 스테이트 패턴(State Pattern) (0) | 2022.10.02 |
[디자인패턴] 어댑터 패턴(Adapter Pattern) (0) | 2022.10.01 |