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.
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 UML class diagram (Ce qui précède est tiré du "Site de support technique pour les ingénieurs informatiques par IT Senka")
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.
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.
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
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))
Le rôle ConcreteHandler
est un rôle spécifique pour traiter une requête.
Dans l'exemple de programme, les classes NoSupport
, LimitSupport
, ʻOddSupportet
SpecialSupport` 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
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()
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)
Recommended Posts