Als Material zum Erlernen von GoF-Entwurfsmustern scheint das Buch "Einführung in Entwurfsmuster, die in der erweiterten und überarbeiteten Java-Sprache gelernt wurden" hilfreich zu sein. Da die aufgeführten Beispiele jedoch auf JAVA basieren, habe ich dieselbe Vorgehensweise mit Python versucht, um mein Verständnis zu vertiefen.
Das englische Wort "Chain of Responsibility" bedeutet "Chain of Responsibility". Dieses Muster erstellt eine Kettenbeziehung zwischen mehreren Objekten, für die eine Anforderung empfangen werden soll, und empfängt nacheinander Anforderungen entlang der erstellten Kettenbeziehung, bis es ein Objekt erreicht, das die Anforderung verarbeiten kann. Es ist ein Muster zu gehen. Durch Anwenden dieses Musters muss die Benutzerseite die Befehlsturmrolle (Verbindung) wie "Diese Anforderung wird von diesem Objekt verarbeitet" und die Benutzerseite "auf ein Objekt in einer Kettenbeziehung" nicht kennen. Die Aufteilung der Rollen ist klar: "Wirf einfach eine Anfrage" und die Verarbeitungsseite "verarbeitet die eingehende Anfrage, wenn sie selbst verarbeitet werden kann, und wenn dies nicht möglich ist, übergebe die Anfrage einfach an das nächste Objekt". (Der Benutzer muss die Details des Prozesses nicht kennen.)
UML class and sequence diagram UML class diagram (Das Obige wird aus der "Website für technischen Support für IT-Ingenieure von IT Senka" zitiert)
Das Muster "Chain of Responsibility" erinnert an den altmodischen "Arbeitsstil" im Bürostil. Anfragen kommen an Menschen. Wenn die Person damit umgehen kann, tun Sie es. Wenn es nicht verarbeitet werden kann, leitet es die Anfrage an die "nächste Person" weiter. Wenn die nächste Person damit umgehen kann, tun Sie es. Wenn es nicht verarbeitet werden kann, wird die Anfrage an "die nächste Person" weitergeleitet. Ich habe das Muster der "Kette der Verantwortung" als ein sogenanntes lineares listenartiges Verarbeitungsmodell verstanden.
Eigentlich möchte ich ein Beispielprogramm ausführen, das das Muster der Verantwortungskette verwendet, und das folgende Verhalten überprüfen.
――Zu der für die Fehlerbehebung erforderlichen Angelegenheit weisen Sie eine "Störungsnummer" zu und lösen Sie das Problem gemäß dem folgenden Arbeitsablauf zur Fehlerbehebung.
<Fehlerbehebung beim Geschäftsablauf>
(1) Legen Sie die Reihenfolge des Drehens der Wannen im Voraus fest ("Alice" -> "Bob" -> "Charlie" -> "Diana" -> "Elmo" -> "Fred").
(2) Zunächst akzeptiert "Alice" die Anforderung zur Fehlerbehebung. Alice
ist eine ** nicht unterstützte ** Rolle, daher wird die Anfrage an den nächsten Bod
weitergeleitet
(3) "Bod" nimmt die Anfrage an. "Bod" ist die Rolle des ** eingeschränkten Supports (Obergrenze der Trouble-Nummer "100") **, und wir werden unser Bestes in dieser Rolle geben und das Geschäft beenden, wenn wir es lösen können. Wenn es nicht gelöst werden kann, leiten Sie die Anfrage an den nächsten "Charlie" weiter
(4) "Charlie" nimmt die Anfrage an. Charlie
ist die Rolle des ** speziellen Supports (Trouble-Nummer ist nur" 429 ") , und wir werden unser Bestes in dieser Rolle geben und das Geschäft beenden, wenn wir es lösen können. Wenn es nicht gelöst werden kann, leiten Sie die Anfrage an die nächste "Diana" weiter
(5) "Diana" nimmt die Anfrage an. Diana
ist die Rolle des ** eingeschränkten Supports (Obergrenze der Trouble-Nummer" 200 "), und wir werden unser Bestes in dieser Rolle geben und das Geschäft beenden, wenn wir es lösen können. Wenn es nicht gelöst werden kann, leiten Sie die Anfrage an den nächsten "Elmo" weiter
(6) "Elmo" nimmt die Anfrage an. Elmo
hat die Rolle, ** nur ungerade Zahlen zu unterstützen ** und wird innerhalb dieses Rollenbereichs sein Bestes geben. Wenn es gelöst werden kann, wird das Geschäft beendet. Wenn es nicht gelöst werden kann, leiten Sie die Anfrage an den nächsten "Fred" weiter
(7) "Fred" nimmt die Anfrage an. Fred
ist die Rolle des ** eingeschränkten Supports (Obergrenze der Trouble-Nummer" 300 ") **, und wir werden unser Bestes in dieser Rolle geben und das Geschäft beenden, wenn wir es lösen können. Wenn es nicht gelöst werden kann, endet es schließlich mit "Nicht lösbar".
$ 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].
Irgendwie war das Ausgabeergebnis schwer zu verstehen. Um das Ausgabeergebnis des Beispielprogramms zu verstehen, scheint es schneller zu sein, die Details des Beispielprogramms zu überprüfen.
Ähnlicher Code wurde in das Git-Repository hochgeladen. https://github.com/ttsubo/study_of_design_pattern/tree/master/Chain_of_Responsibility
--Verzeichnisaufbau
.
├── Main.py
├── support.py
└── trouble.py
Die Rolle "Handler" ist die Rolle, die die Schnittstelle für die Verarbeitung von Anforderungen definiert. Behalten Sie die "nächste Person", und wenn Sie eine Anfrage erhalten, die Sie nicht bearbeiten können, können Sie sie an diese Person senden. Natürlich spielt die "nächste Person" auch die Rolle des "Handlers". Im Beispielprogramm übernimmt die Klasse "Support" diese Rolle. Die Methode, die die Anfrage bearbeitet, war die "Support" -Methode.
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))
Die Rolle "ConcreteHandler" ist eine bestimmte Rolle für die Verarbeitung einer Anforderung. Im Beispielprogramm übernehmen die Klassen "NoSupport", "LimitSupport", "OddSupport" und "SpecialSupport" diese Rolle.
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
Die "Client" -Rolle ist die Rolle, die eine Anforderung an die erste "ConcreteHandler" -Rolle stellt. Im Beispielprogramm übernimmt die Methode "startMain" diese Rolle.
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()
Problemnummern zentral verwalten.
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