Apprenez le modèle de conception «Stratégie» 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.

■ Modèle de stratégie (modèle de stratégie)

Le modèle de stratégie est un modèle de conception dans lequel des algorithmes peuvent être sélectionnés au moment de l'exécution dans le domaine de la programmation informatique. Le modèle de stratégie contient une référence au sous-programme qui décrit l'algorithme à l'intérieur de la structure de données. En plus des pointeurs de fonction, des objets de fonction et des délégués, le polymorphisme et la délégation dans les langages orientés objet orthodoxes ou le typage dynamique de canard par réflexion sont utilisés pour réaliser ce modèle.

UML class and sequence diagram W3sDesign_Strategy_Design_Pattern_UML.jpg

UML class diagram strategy.png (Ce qui précède est cité sur Wikipedia)

□ Mémorandum

Le modèle Strategy sépare délibérément la partie algorithme des autres parties et spécifie uniquement la partie interface avec cet algorithme. Ensuite, l'algorithme est utilisé par délégation du programme. Lors de l'amélioration du programme, si vous utilisez le modèle Strategy, veillez à ne pas changer l'interface du rôle Strategy, il vous suffit de modifier le rôle ConcreteStrategy, et ** la délégation est une délégation graduelle. Parce qu'il utilise des liens, il permet également de basculer facilement entre les algorithmes **.

■ Exemple de programme "Stratégie"

En fait, je voudrais essayer d'exécuter un exemple de programme qui utilise le modèle de stratégie et vérifier le comportement suivant. Ici, ** Taro ** et ** Hanako ** seront en compétition pour la victoire ou la défaite en répétant Janken.


La stratégie de Janken

«Si Taro bat Janken, il défiera le prochain Janken avec la même main. --Hanako défie Janken dans l'ordre "Goo", "Choki", "Par"

$ python Main.py
Even...
Winner:[Hana: 1games,  0win,  0lose]
Winner:[Hana: 2games,  1win,  0lose]
Winner:[Hana: 3games,  2win,  0lose]
Even...
Winner:[Taro: 5games,  0win,  3lose]
Winner:[Hana: 6games,  3win,  1lose]
Winner:[Taro: 7games,  1win,  4lose]
Winner:[Hana: 8games,  4win,  2lose]
Even...

...(snip)

Winner:[Taro: 9976games,  2433win,  5070lose]
Winner:[Hana: 9977games,  5070win,  2434lose]
Winner:[Hana: 9978games,  5071win,  2434lose]
Winner:[Taro: 9979games,  2434win,  5072lose]
Winner:[Hana: 9980games,  5072win,  2435lose]
Even...
Winner:[Hana: 9982games,  5073win,  2435lose]
Even...
Even...
Winner:[Taro: 9985games,  2435win,  5074lose]
Winner:[Hana: 9986games,  5074win,  2436lose]
Winner:[Taro: 9987games,  2436win,  5075lose]
Winner:[Hana: 9988games,  5075win,  2437lose]
Winner:[Taro: 9989games,  2437win,  5076lose]
Winner:[Hana: 9990games,  5076win,  2438lose]
Winner:[Hana: 9991games,  5077win,  2438lose]
Winner:[Taro: 9992games,  2438win,  5078lose]
Winner:[Hana: 9993games,  5078win,  2439lose]
Winner:[Taro: 9994games,  2439win,  5079lose]
Winner:[Hana: 9995games,  5079win,  2440lose]
Winner:[Hana: 9996games,  5080win,  2440lose]
Winner:[Hana: 9997games,  5081win,  2440lose]
Winner:[Hana: 9998games,  5082win,  2440lose]
Even...
Total Result:
[Taro: 10000games,  2440win,  5083lose]
[Hana: 10000games,  5083win,  2440lose]

Le résultat est que la stratégie Janken de ** hanako ** (défier Janken dans l'ordre "goo", "choki", "par") est meilleure que la stratégie Janken de ** Taro **. J'ai fait. C'est parce que la stratégie Janken de ** Taro ** (si vous gagnez le Janken, vous défierez le prochain Janken avec la même main), vous ne pourrez jamais gagner d'affilée.

■ 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/Strategy

.
├── Main.py
└── strategy
    ├── __init__.py
    ├── hand.py
    ├── player.py
    └── strategy.py

(1) Le rôle de la stratégie

C'est le rôle qui définit l'interface d'utilisation de la stratégie. Dans l'exemple de programme, la classe Strategy remplit ce rôle.

strategy/strategy.py


from abc import ABCMeta, abstractmethod

class Strategy(metaclass=ABCMeta):
    @abstractmethod
    def nextHand(self):
        pass

    @abstractmethod
    def study(self, win):
        pass

(2) Le rôle de ConcreteStrategy

C'est le rôle qui implémente en fait l'interface du rôle de «Stratégie». Ici, vous allez effectivement programmer la stratégie spécifique (travail, politique, méthode, algorithme). Dans l'exemple de programme, la classe WinningStrategy et la classe CircularStrategy remplissent ce rôle.

strategy/strategy.py


import random
from strategy.hand import Hand

class WinningStrategy(Strategy):
    def __init__(self):
        self.__won = False
        self.__prevHand = None

    def nextHand(self):
        if not self.__won:
            self.__prevHand = Hand.getHand(random.randint(0, 2))
        return self.__prevHand

    def study(self, win):
        self.__won = win

class CircularStrategy(Strategy):
    def __init__(self):
        self.__Hand = 0

    def nextHand(self):
        return Hand.getHand(self.__Hand)

    def study(self, win):
        self.__Hand = (self.__Hand + 1) % 3

(3) Le rôle du contexte

C'est un rôle qui utilise le rôle «Stratégie». J'ai une instance du rôle ConcreteStrategy et je l'utilise si nécessaire. Dans l'exemple de programme, la classe Player remplit ce rôle.

strategy/player.py


class Player(object):
    def __init__(self, name, strategy):
        self.__name = name
        self.__strategy = strategy
        self.__wincount = 0
        self.__losecount = 0
        self.__gamecount = 0

    def nextHand(self):
        return self.__strategy.nextHand()

    def win(self):
        self.__strategy.study(True)
        self.__wincount += 1
        self.__gamecount += 1

    def lose(self):
        self.__strategy.study(False)
        self.__losecount += 1
        self.__gamecount += 1

    def even(self):
        self.__gamecount += 1

    def __str__(self):
        return "[{0}: {1}games,  {2}win,  {3}lose]".format(self.__name,
                                                           self.__gamecount,
                                                           self.__wincount,
                                                           self.__losecount)

(4) Le rôle du client

Dans l'exemple de programme, la méthode startMain remplit ce rôle.

Main.py


import sys
import strategy.strategy
from strategy.strategy import WinningStrategy, CircularStrategy
from strategy.player import Player

def startMain():
    player1 = Player("Taro", WinningStrategy())
    player2 = Player("Hana", CircularStrategy())

    for _ in range(10000):
        nextHand1 = player1.nextHand()
        nextHand2 = player2.nextHand()
        if nextHand1.isStrongerThan(nextHand2):
            print("Winner:{0}".format(player1))
            player1.win()
            player2.lose()
        elif nextHand2.isStrongerThan(nextHand1):
            print("Winner:{0}".format(player2))
            player1.lose()
            player2.win()
        else:
            print("Even...")
            player1.even()
            player2.even()

    print("Total Result:")
    print(player1)
    print(player2)

if __name__ == '__main__':
    startMain()

(5) Autre

Gérez la victoire ou la défaite de Janken.

strategy/hand.py


class Hand(object):
    HANDVALUE_GUU = 0
    HANDVALUE_CHO = 1
    HANDVALUE_PAA = 2
    name = ["Goo", "Choki", "Par"]
    hands = []

    def __init__(self, handvalue):
        self.__handvalue = handvalue

    @classmethod
    def getHand(cls, handvalue):
        return cls.hands[handvalue]

    def isStrongerThan(self, hand):
        return self.fight(hand) == 1

    def isWeakerThan(self, hand):
        return self.fight(hand) == -1

    def fight(self, hand):
        if self == hand:
            return 0
        elif (self.__handvalue + 1) % 3 == hand.__handvalue:
            return 1
        else:
            return -1

#    def toString(self):
#        return self.name[self.__handvalue]


Hand.hands.append(Hand(Hand.HANDVALUE_GUU))
Hand.hands.append(Hand(Hand.HANDVALUE_CHO))
Hand.hands.append(Hand(Hand.HANDVALUE_PAA))

■ URL de référence

Recommended Posts

Apprenez le modèle de conception «Stratégie» avec Python
Apprenez le modèle de conception "Prototype" avec Python
Apprenez le modèle de conception "Builder" avec Python
Apprenez le modèle de conception "Observer" en Python
Apprenez le modèle de conception "Proxy" en Python
Apprenez le modèle de conception "Commande" en Python
Apprenez le modèle de conception "Visiteur" avec Python
Apprenez le modèle de conception "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Apprenez le modèle de conception "Décorateur" avec Python
Apprenez le modèle de conception "Composite" avec Python
Apprenez le modèle de conception "État" en Python
Apprenez le modèle de conception "Adapter" avec Python
Apprenez le modèle de conception "Abstract Factory" avec Python
Apprenez le modèle de conception "Méthode de modèle" en Python
Apprenez le modèle de conception "Méthode d'usine" en Python
Apprenez le modèle de conception «Chaîne de responsabilité» en Python
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "Façade" avec Python
Implémenter le modèle Singleton en Python
Motif singleton en Python
Modèles de conception en Python: introduction
Python Design Pattern - Méthode de modèle
Obtenir l'API arXiv en Python
Python dans le navigateur: la recommandation de Brython
Enregistrez le fichier binaire en Python
Obtenez le chemin du bureau en Python
Obtenez le chemin du script en Python
Dans la commande python, python pointe vers python3.8
J'ai écrit la file d'attente en Python
Calculer le mois précédent en Python
Examiner la classe d'un objet avec python
Obtenez le chemin du bureau en Python
Obtenez le nom d'hôte en Python
Accéder à l'API Twitter avec Python
La première étape de Python Matplotlib
J'ai écrit la pile en Python
Maîtriser le module lowref en Python
Apprenez les bases de Python ① Débutants élémentaires
Charger le SDK Python distant avec IntelliJ
Essayez d'utiliser l'API Wunderlist en Python
Vérifiez le comportement du destroyer en Python
[Python Kivy] À propos de la modification du thème de conception
Essayez d'utiliser l'API Kraken avec Python
Ecrire le test dans la docstring python
Prenez la somme logique de List en Python (fonction zip)
Modèle de conception du GoF à partir du problème 2. Structure
Afficher Python 3 dans le navigateur avec MAMP
Tweet à l'aide de l'API Twitter en Python
Vérifiez si l'URL existe en Python
Exécuter l'interpréteur Python dans le script
Le résultat de l'installation de python sur Anaconda
Qu'est-ce que "mahjong" dans la bibliothèque Python? ??
Lisez le fichier ligne par ligne avec Python
Lisez le fichier ligne par ligne avec Python
Modèle de conception du GoF à partir du problème 1. Génération
MongoDB avec Python pour la première fois