Apprenez le modèle de conception «Chaîne de responsabilité» en 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.

■ Chaîne de responsabilité (modèle de chaîne de responsabilité)

Le mot anglais «Chain of Responsibility» signifie «chaîne de responsabilité». Ce modèle crée une relation de chaîne entre plusieurs objets pour lesquels une demande doit être reçue et reçoit séquentiellement les demandes le long de la relation de chaîne construite jusqu'à ce qu'il atteigne un objet capable de traiter la demande. C'est un modèle à suivre. En appliquant ce modèle, le côté utilisateur n'a pas à être conscient du rôle de tour de commande (connexion) tel que "cette demande est traitée par cet objet", et du côté utilisateur "à tout objet dans une relation en chaîne". La répartition des rôles devient claire: "il suffit de lancer une requête" et le côté traitement "traite la requête entrante si elle peut être traitée par elle-même, et si ce n'est pas le cas, il suffit de passer la requête à l'objet suivant". (L'utilisateur n'a pas besoin de connaître les détails du processus)

UML class and sequence diagram W3sDesign_Chain_of_Responsibility_Design_Pattern_UML.jpg UML class diagram designpattern-chain_of_responsibility01.gif (Ce qui précède est tiré du "Site de support technique pour les ingénieurs informatiques par IT Senka")

□ Mémorandum

Le modèle «Chaîne de responsabilité» rappelle le «style de travail» à l'ancienne. Les demandes arrivent aux gens. Si la personne peut le gérer, faites-le. S'il ne peut pas être traité, il transmet la demande à la «personne suivante». Si la personne suivante peut le gérer, faites-le. Si elle ne peut être traitée, la demande est transmise à «la personne suivante». J'ai compris le modèle de «Chaîne de responsabilité» comme un modèle de traitement de type liste linéaire.

Chain_of_responsibility.png

■ Exemple de programme «Chaîne de responsabilité»

En fait, je voudrais exécuter un exemple de programme qui utilise le modèle de chaîne de responsabilité et vérifier le comportement suivant.

―― Pour les questions nécessaires au dépannage, attribuez un «numéro de problème» et résolvez le problème en fonction du flux commercial de résolution des problèmes suivant. --Lorsque le problème est résolu, le résultat de la solution est affiché. --Si le problème ne peut pas être résolu, il se terminera par "Incoluble".

<Dépannage du flux commercial> (1) Décidez à l'avance de l'ordre de rotation des cuves ("Alice" -> "Bob" -> "Charlie" -> "Diana" -> "Elmo" -> "Fred") (2) Premièrement, ʻAlice accepte la demande de dépannage. ʻAlice est un ** rôle non pris en charge **, alors faites circuler la demande au Bod suivant (3) «Bod» accepte la demande. Bod est le rôle de ** support limité (limite supérieure du numéro de problème" 100 ") **, et nous ferons de notre mieux dans cette plage de rôles et mettrons fin à l'entreprise si nous pouvons le résoudre. S'il ne peut pas être résolu, faites circuler la demande au prochain Charlie (4) «Charlie» accepte la demande. Charlie est le rôle du ** support spécial (le numéro du problème est" 429 "uniquement) , et nous ferons de notre mieux dans ce rôle et mettrons fin à l'entreprise si nous pouvons le résoudre. S'il ne peut pas être résolu, faites circuler la demande à la prochaine Diana (5) «Diana» accepte la demande. Diana est le rôle de ** support limité (limite supérieure du numéro de problème" 200 "), et nous ferons de notre mieux dans ce rôle et mettrons fin à l'entreprise si nous pouvons le résoudre. S'il ne peut pas être résolu, faites circuler la demande au prochain «Elmo» (6) ʻElmo accepte la demande. ʻElmo a un rôle de ** ne supportant que les nombres impairs **, et fera de son mieux dans cette plage de rôles, et s'il peut être résolu, il mettra fin à l'entreprise. S'il ne peut pas être résolu, transmettez la demande au prochain Fred (7) Fred accepte la demande. Fred est le rôle de ** support restreint (limite supérieure du numéro de problème" 300 ") **, et nous ferons de notre mieux dans ce rôle et mettrons fin à l'entreprise si nous pouvons le résoudre. S'il ne peut pas être résolu, il se terminera par "Incoluble"

$ python Main.py 
[Trouble 0] is resolved by [Bob].
[Trouble 33] is resolved by [Bob].
[Trouble 66] is resolved by [Bob].
[Trouble 99] is resolved by [Bob].
[Trouble 132] is resolved by [Diana].
[Trouble 165] is resolved by [Diana].
[Trouble 198] is resolved by [Diana].
[Trouble 231] is resolved by [Elmo].
[Trouble 264] is resolved by [Fred].
[Trouble 297] is resolved by [Elmo].
[Trouble 330] cannot be resolved.
[Trouble 363] is resolved by [Elmo].
[Trouble 396] cannot be resolved.
[Trouble 429] is resolved by [Charlie].
[Trouble 462] cannot be resolved.
[Trouble 495] is resolved by [Elmo].

D'une manière ou d'une autre, le résultat de sortie était difficile à comprendre. Pour comprendre le résultat de sortie de l'exemple de programme, il semble plus rapide de vérifier les détails de l'exemple de programme.

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

.
├── Main.py
├── support.py
└── trouble.py

(1) Le rôle du Handler

Le rôle Handler est le rôle qui définit l'interface de traitement des requêtes. Gardez la "personne suivante", et si vous recevez une demande que vous ne pouvez pas traiter, vous pouvez l'envoyer à cette personne. Bien entendu, la "personne suivante" joue également le rôle de "Handler". Dans l'exemple de programme, la classe Support remplit ce rôle. La méthode qui gère la demande était la méthode support.

support.py


from abc import ABCMeta, abstractmethod

class Support(metaclass=ABCMeta):
    def __init__(self, name):
        self.__name = name
        self.__next = None

    def setNext(self, next):
        self.__next = next
        return next

    def support(self, trouble):
        if self.resolve(trouble):
            self.done(trouble)
        elif self.__next is not None:
            self.__next.support(trouble)
        else:
            self.fail(trouble)

    def __str__(self):
        return "[{0}]".format(self.__name)

    @abstractmethod
    def resolve(self, trouble):
        pass

    def done(self, trouble):
        print("{0} is resolved by {1}.".format(trouble, self))

    def fail(self, trouble):
        print("{0} cannot be resolved.".format(trouble))

(2) Le rôle de ConcreteHandler

Le rôle ConcreteHandler est un rôle spécifique pour traiter une requête. Dans l'exemple de programme, les classes NoSupport, LimitSupport, ʻOddSupportetSpecialSupport` remplissent ce rôle.

support.py


class NoSupport(Support):
    def __init__(self, name):
        super(NoSupport, self).__init__(name)

    def resolve(self, trouble):
        return False

class LimitSupport(Support):
    def __init__(self, name, limit):
        super(LimitSupport, self).__init__(name)
        self.__limit = limit

    def resolve(self, trouble):
        return True if trouble.getNumber() < self.__limit else False

class OddSupport(Support):
    def __init__(self, name):
        super(OddSupport, self).__init__(name)

    def resolve(self, trouble):
        return True if trouble.getNumber() % 2 == 1 else False

class SpecialSupport(Support):
    def __init__(self, name, number):
        super(SpecialSupport, self).__init__(name)
        self.__number = number

    def resolve(self, trouble):
        return True if trouble.getNumber() == self.__number else False

(3) Le rôle du client

Le rôle Client est le rôle qui fait une demande au premier rôle ConcreteHandler. Dans l'exemple de programme, la méthode startMain remplit ce rôle.

Main.py


from support import NoSupport, LimitSupport, SpecialSupport, OddSupport
from trouble import Trouble

def startMain():
    alice = NoSupport("Alice")
    bob = LimitSupport("Bob", 100)
    charlie = SpecialSupport("Charlie", 429)
    diana = LimitSupport("Diana", 200)
    elmo = OddSupport("Elmo")
    fred = LimitSupport("Fred", 300)

    alice.setNext(bob).setNext(charlie).setNext(diana).setNext(elmo).setNext(fred)

    for i in range(0, 500, 33):
        alice.support(Trouble(i))

if __name__ == '__main__':
    startMain()

(4) Autre

Gérez de manière centralisée les numéros de problème.

trouble.py


class Trouble:
    def __init__(self, number):
        self.__number = number

    def getNumber(self):
        return self.__number

    def __str__(self):
        return '[Trouble {0}]'.format(self.__number)

■ URL de référence

Recommended Posts

Apprenez le modèle de conception «Chaîne de responsabilité» en 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 "Flyweight" en Python
Apprenez le modèle de conception "Observer" en Python
Apprenez le modèle de conception "Memento" avec 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 "Bridge" avec Python
Apprenez le modèle de conception "Mediator" avec Python
Apprenez le modèle de conception "Iterator" avec Python
Apprenez le modèle de conception «Stratégie» 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
Modèle de chaîne de responsabilité en Java
Apprenez le modèle de conception "Singleton" avec Python
Apprenez le modèle de conception "Façade" avec Python
[Gang of Four] Apprentissage des modèles de conception - Chaîne de responsabilité
Implémenter le modèle Singleton en Python
Apprenez les bases de Python ① Débutants élémentaires
Vérifiez le comportement du destroyer en Python
Le résultat de l'installation de python sur Anaconda
Principes de base pour exécuter NoxPlayer en Python
À la recherche du FizzBuzz le plus rapide en Python
Apprenez intuitivement la refonte de Python np
Sortie du nombre de cœurs de processeur en Python
[Python] Trier la liste de pathlib.Path dans l'ordre naturel
Récupérer l'appelant d'une fonction en Python
Faites correspondre la distribution de chaque groupe en Python
Afficher le résultat du traitement de la géométrie en Python
Copiez la liste en Python
Trouvez la solution de l'équation d'ordre n avec python
L'histoire de la lecture des données HSPICE en Python
[Note] À propos du rôle du trait de soulignement "_" en Python
Résolution d'équations de mouvement en Python (odeint)
Sortie sous la forme d'un tableau python
Motif singleton en Python
Modèle de visiteur en Python
Découvrez la bonne efficacité de calcul de la vectorisation en Python
Apprenez Nim avec Python (dès le début de l'année).
[python] Récupère la liste des classes définies dans le module
L'histoire de FileNotFound en Python open () mode = 'w'
Implémenter la solution de l'algèbre de Riccati en Python
Obtenir la taille (nombre d'éléments) de Union Find en Python
Ne pas être conscient du contenu des données en python
Reproduire l'exemple d'exécution du chapitre 4 de Hajipata en Python
Utilisons les données ouvertes de "Mamebus" en Python
Implémentation de l'algorithme "Algorithm Picture Book" en Python3 (Heap Sort Edition)
[Python] Affiche toutes les combinaisons d'éléments de la liste
Obtenez l'URL de la destination de la redirection HTTP en Python
Un mémorandum sur la mise en œuvre des recommandations en Python
Reproduire l'exemple d'exécution du chapitre 5 de Hajipata en Python
Pour faire l'équivalent de Ruby ObjectSpace._id2ref en Python
Vérifiez la nature atrophique de la distribution de probabilité en Python
J'ai étudié les modèles de conception (mémo personnel) Partie 6 (modèle de chaîne de responsabilité, modèle de façade, modèle de médiateur)
Vers la retraite de Python2