memento
(사람, 장소를 기억하기 위한) 기념품 (=souvenir)
오브젝트의 상태를 사진처럼 memento로 보관하고 필요할 때 꺼내서 그 상태로 되돌릴 수 있는 패턴
일반적으로 어떤 객체의 히스토리를 관리하고 싶을 때 유용한 패턴
게임에서 save를 하는 것과 비슷한 원리
이전의 상태로 되돌릴 수 있다.
되돌리는 것은 직전 과거도 가능하고 단계별로도 가능하다.
단 undo를 실행하려면 인스턴스가 가지고 있는 정보(state)를 따로 저장할 필요가 있다. 그것을 원래대로 되돌릴 수 있어야 한다.
메멘토 패턴을 사용하면 어떤 시점의 인스턴스 상태를 확실하게 기록해서 저장해 두면 나중에 인스턴스를 그 시점의 상태로 되돌릴 수 있다.


과일을 모으는 주사위 게임
1. 이 게임은 자동적으로 진행됨
2. 게임의 주인공은 주사위를 던져 나온 수가 다음 상태를 결정함
3. 좋은 수가 나오면 주인공의 돈이 증가함
4. 나쁜 수가 나오면 돈이 감소함
5. 특별히 좋은 수가 나오면 주인공이 과일을 받음
6. 돈이 없어지면 종료
메멘토 패턴의 활용
- 프로그램 내에서 돈이 모였을 때 미래를 대비하여 Memento 클래스의 인스턴스를 생성하여 현재 상태를 저장함
- 만약, 계속 져서 돈이 줄어들면, 더 줄어들기 전에 저장해 둔 Memento의 인스턴스를 사용해서 이전의 상태로 복원함
- 게임할 때 질 것 같으면 저장해두는 방법으로 결국 게임에서 돈을 많이 모을 수 있도록 하기 위해 메멘토 패턴을 사용해 본다.
import random
import time
class Memento:
def __init__(self, money):
self.money = money
self.fruits = []
def getMoney(self):
return self.money
def addFruit(self, fruit):
self.fruits.append(fruit)
def getFruits(self):
return self.fruits
import random
class Gamer:
def __init__(self, money):
self.money = money
self.fruits = []
self.fruitsName = ["사과", "포도", "바나나", "귤"]
self.memento = None # 멤버 변수 추가
def getMoney(self):
return self.money
def getFruit(self):
fn = len(self.fruitsName)
fruitName = self.fruitsName[random.randint(0, fn - 1)]
return "맛있는 " + fruitName
def bet(self):
dice = random.randint(1, 6)
if dice == 1:
self.money += 100
print("소지금 증가")
elif dice == 2:
self.money //= 2 # 정수 나눗셈으로 변경
print("소지금 절반 감소")
elif dice == 6:
f = self.getFruit()
print("과일 " + f + "를 받았습니다.")
self.fruits.append(f)
else:
print("아무것도 변한 것이 없습니다.")
def createMemento(self):
m = Memento(self.money)
for f in self.fruits: # deep copy
m.addFruit(f)
return m
def restoreMemento(self, memento):
self.money = memento.money
self.fruits = memento.fruits
def printState(self):
print("[money: " + str(self.money) + ", fruits: ", end="")
for f in self.fruits:
print(", " + f, end="")
print("]")
def gameRun():
print("game start")
gamer = Gamer(100) # Gamer 객체 생성 (초기 자금 100)
memento = gamer.createMemento() # 초기 상태 저장
for i in range(100): # 100번 게임 진행
print("=== game turn ===", str(i))
gamer.printState() # 현재 상태 출력
gamer.bet() # 게임 진행 (주사위 굴리기)
print("소지금이 " + str(gamer.getMoney()) + "원이 되었습니다.")
# 메멘토 취급 결정
if gamer.getMoney() > memento.getMoney(): # 돈을 많이 땄을 때
print("게임을 잘 하고 있으니 현재 상태를 저장")
memento = gamer.createMemento() # 현재 상태 저장
elif gamer.getMoney() < memento.getMoney() / 2: # 돈을 많이 잃었을 때
print("소지금이 너무 많이 감소해서 이전의 상태로 다시 복원")
gamer.restoreMemento(memento) # 이전 상태로 복원
time.sleep(0.5) # 0.5초 대기
print() # 빈 줄 출력
gameRun() # 게임 실행