[GO] Apprenez le modèle de conception "Memento" avec Python

En tant que matériel d'apprentissage des modèles de conception du GoF, le livre «Introduction aux modèles de conception appris dans le langage Java augmenté et révisé» semble être utile. Cependant, comme les exemples repris sont basés sur JAVA, j'ai essayé la même pratique avec Python pour approfondir ma compréhension.

■ Memento (motif Memento)

Le mot anglais "Memento" signifie "souvenir / mémorial". Ce modèle est un modèle qui fournit un périphérique pour mémoriser (enregistrer) l'état d'un objet à tout moment et le remettre ultérieurement à cet état. (L'état peut être restauré sans détruire l'encapsulation) En d'autres termes, un modèle pour fournir la fonction «annuler» (annuler l'opération et revenir à l'état avant l'opération) telle qu'implémentée dans les éditeurs de texte, etc. est. Il est à noter que seules les informations minimales nécessaires (valeur de champ) pour restaurer l'état sont enregistrées. (Ce qui précède est tiré du "Site de support technique pour les ingénieurs informatiques par IT Senka")

UML class and sequence diagram W3sDesign_Memento_Design_Pattern_UML.jpg (Ce qui précède est cité sur Wikipedia)

■ Exemple de programme "Memento"

En fait, je voudrais exécuter un exemple de programme qui utilise le modèle Memento et vérifier le comportement suivant. De plus, l'exemple de programme ** "Jeu de dés pour ramasser des fruits" ** suppose les opérations suivantes.


Mouvement selon les yeux des dés

  1. Lorsque le jet de dés est "1" </ font>, votre argent augmentera ** 100 yens **
  2. Lorsque le jet de dés est "2" </ font>, le montant d'argent dont vous disposez est de ** moitié ** (les fractions sont arrondies vers le bas).
  3. Lorsque les dés lancés "6" </ font>, vous obtiendrez ** fruit ** (Vous pouvez obtenir des ** "fruits" ** normaux, mais vous pouvez obtenir des ** "fruits délicieux" **, la probabilité est de 50%)
  4. Si d'autres dés lancent, rien ne se passe
$ python Main.py 
==== 0
Statut actuel:[money = 100, fruits = []]
j'ai plus d'argent
Le montant d'argent que j'ai est maintenant de 200 yens
      (Il a beaucoup augmenté, alors sauvegardons l'état actuel)

==== 1
Statut actuel:[money = 200, fruits = []]
des fruits(De délicieux raisins)j'ai eu
Le montant d'argent que j'ai est maintenant de 200 yens

==== 2
Statut actuel:[money = 200, fruits = ['De délicieux raisins']]
Rien ne s'est passé
Le montant d'argent que j'ai est maintenant de 200 yens

==== 3
Statut actuel:[money = 200, fruits = ['De délicieux raisins']]
j'ai plus d'argent
Le montant d'argent que j'ai est maintenant de 300 yens
      (Il a beaucoup augmenté, alors sauvegardons l'état actuel)


...(snip)


==== 22
Statut actuel:[money = 500, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Pomme', 'banane']]
des fruits(Délicieuse banane)j'ai eu
Le montant d'argent que j'ai est maintenant de 500 yens

==== 23
Statut actuel:[money = 500, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Pomme', 'banane', 'Délicieuse banane']]
j'ai plus d'argent
Le montant d'argent que j'ai est maintenant de 600 yens
      (Il a beaucoup augmenté, alors sauvegardons l'état actuel)

==== 24
Statut actuel:[money = 600, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Pomme', 'banane', 'Délicieuse banane']]
Le montant d'argent dont vous disposez a été réduit de moitié
Le montant d'argent que j'ai est maintenant de 300 yens

==== 25
Statut actuel:[money = 300, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Pomme', 'banane', 'Délicieuse banane']]
Rien ne s'est passé
Le montant d'argent que j'ai est maintenant de 300 yens

==== 26
Statut actuel:[money = 300, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Pomme', 'banane', 'Délicieuse banane']]
Le montant d'argent dont vous disposez a été réduit de moitié
Le montant d'argent que j'ai est maintenant de 150 yens
      (Il a beaucoup diminué, revenons donc à l'état précédent)

==== 27
Statut actuel:[money = 600, fruits = ['De délicieux raisins', 'De délicieux raisins', 'Délicieuse banane', 'Délicieuse pomme', 'Délicieuse banane']]
Le montant d'argent dont vous disposez a été réduit de moitié
Le montant d'argent que j'ai est maintenant de 300 yens

...(snip)

À la fin, j'ai pu confirmer l'opération en utilisant le modèle Memento.

■ Détails de l'exemple de programme

Un code similaire a été téléchargé dans le référentiel Git. https://github.com/ttsubo/study_of_design_pattern/tree/master/Memento

  • Structure du répertoire
.
├── Main.py
└── memento
    ├── __init__.py
    ├── gamer.py
    └── memento.py

(1) Le rôle de l'auteur

Le rôle ʻOriginator crée un rôle Memento lorsque vous voulez sauvegarder votre état actuel. Le rôle ʻOriginator également, une fois passé le rôle Memento précédent, retourne à l'état dans lequel il se trouvait lorsque le rôle Memento a été créé. Dans l'exemple de programme, la classe Gamer remplit ce rôle.

memento/gamer.py


import random
from memento.memento import Memento

class Gamer(object):
    def __init__(self, money):
        self.__fruitname = ["Pomme", "Grain de raisin", "banane", "Mandarine"]
        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("j'ai plus d'argent")
        elif dice == 2:
            self.__money //= 2
            print("Le montant d'argent dont vous disposez a été réduit de moitié")
        elif dice == 6:
            f = self.__getFruit()
            print("des fruits({0})j'ai eu".format(f))
            self.__fruits.append(f)
        else:
            print("Rien ne s'est passé")

    def createMemento(self):
        m = Memento(self.__money)
        for f in self.__fruits:
            if f.startswith("Délicieux"):
                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 = "Délicieux"
        return prefix + random.choice(self.__fruitname)

(2) Le rôle de Memento (souvenir)

Le rôle Memento résume les informations internes du rôle ʻOriginator. Le rôle Memento a des informations internes sur le rôle ʻOriginator, mais ces informations ne sont pas communiquées à tout le monde. Dans l'exemple de programme, la classe Memento remplit ce rôle.

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

(3) Le rôle du gardien

Le rôle Caretaker indique au rôle ʻOriginator lorsque vous voulez sauvegarder l'état actuel du rôle ʻOriginator. Le rôle ʻOriginatorle reçoit, crée un rôleMemento et le transmet au rôle Caretaker. Le rôle Caretaker enregistre le rôle Mementopour les besoins futurs. Dans l'exemple de programme, la méthodestartMain` remplit ce rôle.

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("Statut actuel:{0}".format(gamer))
        gamer.bet()
        print("L'argent que tu as{0}C'est devenu un cercle".format(gamer.getMoney()))

        if gamer.getMoney() > memento.getMoney():
            print("      (Il a beaucoup augmenté, alors sauvegardons l'état actuel)")
            memento = gamer.createMemento()
        elif gamer.getMoney() < memento.getMoney() / 2:
            print("      (Il a beaucoup diminué, revenons donc à l'état précédent)")
            gamer.restoreMemento(memento)

        time.sleep(1)
        print("")

if __name__ == '__main__':
    startMain()

■ URL de référence

Recommended Posts