As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.
The English word "Memento" means "keepsake / memorial". This pattern is a pattern that provides a device to remember (save) the state of an object at any point in time and later return the object to that state. (The state can be restored without destroying the encapsulation) In other words, a pattern for providing the "undo" (cancel the operation and return to the state before the operation) function as implemented in a text editor etc. is. It should be noted that only the minimum necessary information (field value) to restore the state is saved. (The above is quoted from "Technical support site for IT engineers by IT Senka")
UML class and sequence diagram (The above is quoted from Wikipedia)
Actually, I would like to run a sample program that utilizes the Memento pattern and check the following behavior. In addition, the sample program ** "Dice game for collecting fruits" ** assumes the following operations.
--This game will proceed automatically ――The main character of the game rolls the dice, and the action is decided according to the dice roll. --Displays the current status of each game (money you have, fruits you have) --At the start of the game, start with a possession of 100 yen -** If the current amount of money exceeds the amount of money you have saved, save the situation (the amount of money you have and the "delicious fruit" you have) ** -** If the current amount of money is less than half of the amount of money you have saved, restore the previously saved situation (money, "delicious fruit" you have) as the current situation. Masu ** ――It will end when you run out of money. --Repeat the game up to 100 times
Movement according to the dice
$ python Main.py
==== 0
Current status:[money = 100, fruits = []]
I have more money
The amount of money I have is now 200 yen
(It has increased a lot, so let's save the current state)
==== 1
Current status:[money = 200, fruits = []]
fruits(Delicious grapes)I got
The amount of money I have is now 200 yen
==== 2
Current status:[money = 200, fruits = ['Delicious grapes']]
Nothing happened
The amount of money I have is now 200 yen
==== 3
Current status:[money = 200, fruits = ['Delicious grapes']]
I have more money
The amount of money I have is now 300 yen
(It has increased a lot, so let's save the current state)
...(snip)
==== 22
Current status:[money = 500, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Apple', 'banana']]
fruits(Delicious banana)I got
The amount of money I have is now 500 yen
==== 23
Current status:[money = 500, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Apple', 'banana', 'Delicious banana']]
I have more money
The amount of money I have is now 600 yen
(It has increased a lot, so let's save the current state)
==== 24
Current status:[money = 600, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Apple', 'banana', 'Delicious banana']]
Your money has been halved
The amount of money I have is now 300 yen
==== 25
Current status:[money = 300, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Apple', 'banana', 'Delicious banana']]
Nothing happened
The amount of money I have is now 300 yen
==== 26
Current status:[money = 300, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Apple', 'banana', 'Delicious banana']]
Your money has been halved
The amount of money I have is now 150 yen
(It has decreased a lot, so let's return to the previous state)
==== 27
Current status:[money = 600, fruits = ['Delicious grapes', 'Delicious grapes', 'Delicious banana', 'Delicious apple', 'Delicious banana']]
Your money has been halved
The amount of money I have is now 300 yen
...(snip)
At the end, I was able to confirm the operation using the Memento
pattern.
Similar code has been uploaded to the Git repository. https://github.com/ttsubo/study_of_design_pattern/tree/master/Memento
--Directory structure
.
├── Main.py
└── memento
├── __init__.py
├── gamer.py
└── memento.py
The ʻOriginator role creates a
Memento role when you want to save your current state. The ʻOriginator
role also, when passed the previous Memento
role, returns to the state it was in when the Memento
role was created.
In the sample program, the Gamer
class serves this role.
memento/gamer.py
import random
from memento.memento import Memento
class Gamer(object):
def __init__(self, money):
self.__fruitname = ["Apple", "Grape", "banana", "Mandarin orange"]
self.__money = money
self.__fruits = []
def getMoney(self):
return self.__money
def bet(self):
dice = random.randint(1, 6)
if dice == 1:
self.__money += 100
print("I have more money")
elif dice == 2:
self.__money //= 2
print("Your money has been halved")
elif dice == 6:
f = self.__getFruit()
print("fruits({0})I got".format(f))
self.__fruits.append(f)
else:
print("Nothing happened")
def createMemento(self):
m = Memento(self.__money)
for f in self.__fruits:
if f.startswith("Delicious"):
m.addFruit(f)
return m
def restoreMemento(self, memento):
self.__money = memento.money
self.__fruits = memento.getFruits()
def __str__(self):
return "[money = {0}, fruits = {1}]".format(self.__money, self.__fruits)
def __getFruit(self):
prefix = ''
if bool(random.getrandbits(1)):
prefix = "Delicious"
return prefix + random.choice(self.__fruitname)
The Memento
role summarizes the internal information of the ʻOriginatorrole. The
Memento role has internal information about the ʻOriginator
role, but that information is not disclosed to everyone.
In the sample program, the Memento
class serves this role.
memento/memento.py
class Memento(object):
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
The Caretaker
role tells the ʻOriginator role when you want to save the current state of the ʻOriginator
role. The ʻOriginatorrole receives it, creates a
Memento role, and passes it to the
Caretakerrole. The
Caretaker role saves the
Mementorole for future needs. In the sample program, the
startMain` method serves this role.
Main.py
import time
from memento.gamer import Gamer
def startMain():
gamer = Gamer(100)
memento = gamer.createMemento()
for i in range(100):
print("==== {0}".format(i))
print("Current status:{0}".format(gamer))
gamer.bet()
print("The money you have{0}It became a circle".format(gamer.getMoney()))
if gamer.getMoney() > memento.getMoney():
print(" (It has increased a lot, so let's save the current state)")
memento = gamer.createMemento()
elif gamer.getMoney() < memento.getMoney() / 2:
print(" (It has decreased a lot, so let's return to the previous state)")
gamer.restoreMemento(memento)
time.sleep(1)
print("")
if __name__ == '__main__':
startMain()
-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2)
Recommended Posts