[GO] Lernen Sie das Entwurfsmuster "Besucher" mit Python

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.

■ Besuchermuster (Besuchermuster)

Das Besuchermuster ist ein Entwurfsmuster zum Trennen von Algorithmen von der Struktur von Objekten in der objektorientierten Programmierung und Softwareentwicklung. Als praktisches Ergebnis der Trennung können neue Operationen an vorhandenen Objekten hinzugefügt werden, ohne die Struktur zu ändern. Grundsätzlich können Sie mit dem Besuchermuster einer Gruppe von Klassen neue virtuelle Funktionen hinzufügen, ohne die Klasse selbst zu ändern. Erstellen Sie dazu eine Besucherklasse, die sich ordnungsgemäß auf alle virtuellen Funktionen spezialisiert hat. Der Besucher nimmt einen Verweis auf die Instanz als Eingabe und verwendet den doppelten Versand, um sein Ziel zu erreichen. Besucher sind leistungsstark, haben aber auch Einschränkungen im Vergleich zu vorhandenen virtuellen Funktionen. Sie müssen innerhalb jeder Klasse eine kleine Rückrufmethode hinzufügen, und die Rückrufmethode jeder Klasse kann nicht von einer neuen Unterklasse geerbt werden.

UML class and sequence diagram W3sDesign_Visitor_Design_Pattern_UML.jpg

UML class diagram Visitor_design_pattern.svg.png

□ Memorandum

Dies ist ein Zitat aus dem Buch "Einführung in Designmuster, die in der Java-Sprache gelernt wurden", aber ich hatte Hunger.

Besucher bedeutet "Besucher". Angenommen, Sie haben viele Elemente in Ihrer Datenstruktur gespeichert und möchten für jedes Element eine "Verarbeitung" durchführen. Wo soll der "Verarbeitungs" -Code zu diesem Zeitpunkt geschrieben werden? Wenn Sie normal darüber nachdenken, schreiben Sie es in eine Klasse, die die Datenstruktur darstellt. Aber was ist, wenn die "Verarbeitung" nicht immer ein Typ ist? In diesem Fall müsste die Datenstrukturklasse jedes Mal geändert werden, wenn eine neue Verarbeitung erforderlich wäre. Das Besuchermuster ** trennt Datenstruktur und Verarbeitung **. Bereiten Sie dann eine Klasse vor, die den "Besucher" darstellt, der der Hauptteil der Datenstruktur ist, und lassen Sie diese Klasse die Verarbeitung übernehmen. Wenn Sie dann einen neuen Prozess hinzufügen möchten, können Sie einen neuen "Besucher" erstellen. Und die Datenstruktur sollte die "Besucher" akzeptieren, die die Tür öffnen.

■ Beispielprogramm "Besucher"

Eigentlich möchte ich ein Beispielprogramm ausführen, das das Besuchermuster verwendet, und das folgende Verhalten überprüfen. Das Verhalten ist übrigens das gleiche wie im Beispielprogramm in Qiita-Artikel "Lernen Sie das Entwurfsmuster" Composite "mit Python". Vergleichen Sie daher die Implementierungen. Dies gibt Ihnen ein besseres Verständnis des Besuchermusters.

$ python Main.py 
Making root entries
/root (30000)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (0)

Making user entries...
/root (31500)
/root/bin (30000)
/root/bin/vi (10000)
/root/bin/latex (20000)
/root/tmp (0)
/root/usr (1500)
/root/usr/yuki (300)
/root/usr/yuki/diary.html (100)
/root/usr/yuki/composite.py (200)
/root/usr/hanako (300)
/root/usr/hanako/memo.tex (300)
/root/usr/tomura (900)
/root/usr/tomura/game.doc (400)
/root/usr/tomura/junk.mail (500)

Occurring Exception...
FileTreatmentException

■ Details zum Beispielprogramm

Ähnlicher Code wurde in das Git-Repository hochgeladen. https://github.com/ttsubo/study_of_design_pattern/tree/master/Visitor

--Verzeichnisaufbau

.
├── Main.py
└── visitor
    ├── __init__.py
    ├── element.py
    └── visitor.py

(1) Die Rolle eines Besuchers

Die Rolle "Besucher" deklariert eine Besuchsmethode (xxxx) mit der Angabe "besucht xxxx" für jedes bestimmte Element der Datenstruktur (Rolle "ConcreteElement"). visit (xxxx) ist eine Methode zur Verarbeitung von xxxx. Der eigentliche Code wird auf der Seite der Rolle "Konkreter Besucher" geschrieben. Im Beispielprogramm übernimmt die Klasse "Besucher" diese Rolle.

visitor/visitor.py


from abc import ABCMeta, abstractmethod

class Vistor(metaclass=ABCMeta):
    @abstractmethod
    def visit(self, directory):
        pass

(2) Die Rolle des konkreten Besuchers

Die Rolle "ConcreteVisitor" implementiert die Schnittstelle für die Rolle "Besucher". Implementieren Sie eine Methode des Formularbesuchers (xxxx) und beschreiben Sie die Verarbeitung für jede Rolle "ConcreteElement". Im Beispielprogramm übernimmt die Klasse "ListVistor" diese Rolle.

visitor/visitor.py


class ListVistor(Vistor):
    def __init__(self):
        self.__currentdir = ''

    def visit(self, directory):
        print("{0}/{1}".format(self.__currentdir, directory))
        if isinstance(directory, Directory):
            savedir = self.__currentdir
            self.__currentdir = self.__currentdir + '/' + directory.getName()
            for f in directory:
                f.accept(self)
            self.__currentdir = savedir

(3) Rolle des Elements

Die Rolle "Element" ist eine Rolle, die das Ziel der Rolle "Besucher" darstellt. Deklarieren Sie eine Akzeptanzmethode, die den Besuch akzeptiert. Die Rolle "Besucher" wird an das Argument der Methode "accept" übergeben. Im Beispielprogramm übernimmt die Klasse "Element" diese Rolle.

visitor/element.py


from abc import ABCMeta, abstractmethod

class Element(metaclass=ABCMeta):
    @abstractmethod
    def accept(self, v):
        pass

(4) Rolle von ConcreteElement

Die Rolle "ConcreteElement" ist die Rolle, die die Schnittstelle für die Rolle "Element" implementiert. Im Beispielprogramm übernehmen die Klassen "Eintrag", "Datei" und "Verzeichnis" diese Rolle.

visitor/element.py


class Entry(Element):
    @abstractmethod
    def getName(self):
        pass

    @abstractmethod
    def getSize(self):
        pass

    def add(self, entry):
        raise FileTreatmentException

    def __str__(self):
        return "{0} ({1})".format(self.getName(), self.getSize())


class File(Entry):
    def __init__(self, name, size):
        self.__name = name
        self.__size = size

    def getName(self):
        return self.__name

    def getSize(self):
        return self.__size

    def accept(self, v):
        v.visit(self)


class Directory(Entry):
    def __init__(self, name):
        self.__name = name
        self.__dir = []

    def getName(self):
        return self.__name

    def getSize(self):
        size = 0
        for f in self.__dir:
            size += f.getSize()
        return size

    def add(self, entry):
        self.__dir.append(entry)
        return self
    
    def __iter__(self):
        self.__index = 0
        return self

    def __next__(self):
        if self.__index >= len(self.__dir):
            raise StopIteration()
        dir = self.__dir[self.__index]
        self.__index += 1
        return dir

    def accept(self, v):
        v.visit(self)

(5) Die Rolle der Objektstruktur

Die Rolle "Objektstruktur" ist eine Rolle, die eine Reihe von "Element" -Rollen verarbeitet. Es verfügt über eine Methode, mit der die Rolle "ConcreteVisitor" einzelne "Element" -Rollen verarbeiten kann. Im Beispielprogramm übernimmt die Klasse "Directory" diese Rolle. (Zwei Rollen pro Person) Die "Directory" -Klasse des Beispielprogramms stellt einen "Iterator" bereit, sodass die "ConcreteVisitor" -Rolle einzelne "Element" -Rollen verarbeiten kann.

(6) Die Rolle des Kunden

Im Beispielprogramm übernimmt die Methode "startMain" diese Rolle.

Main.py


from visitor.visitor import ListVistor
from visitor.element import File, Directory, FileTreatmentException

def startMain():
    try:
        print("Making root entries")
        rootdir = Directory("root")
        bindir = Directory("bin")
        tmpdir = Directory("tmp")
        usrdir = Directory("usr")

        rootdir.add(bindir)
        rootdir.add(tmpdir)
        rootdir.add(usrdir)

        bindir.add(File("vi", 10000))
        bindir.add(File("latex", 20000))
        rootdir.accept(ListVistor())

        print("")

        print("Making user entries...")
        yuki = Directory("yuki")
        hanako = Directory("hanako")
        tomura = Directory("tomura")

        usrdir.add(yuki)
        usrdir.add(hanako)
        usrdir.add(tomura)

        yuki.add(File("diary.html", 100))
        yuki.add(File("composite.py", 200))
        hanako.add(File("memo.tex", 300))
        tomura.add(File("game.doc", 400))
        tomura.add(File("junk.mail", 500))
        rootdir.accept(ListVistor())

        print("")
        print("Occurring Exception...")
        tmpfile = File("tmp.txt", 100)
        bindir = Directory("bin")
        tmpfile.add(bindir)
    except FileTreatmentException as ex:
        print(ex.message)

if __name__ == '__main__':
    startMain()

(7) Andere

Fügen Sie eine Ausnahmeklasse hinzu

visitor/element.py


class FileTreatmentException(Exception):
    def __init__(self,*args,**kwargs):
        self.message = "FileTreatmentException"

■ Referenz-URL

Recommended Posts

Lernen Sie das Entwurfsmuster "Besucher" mit Python
Lernen Sie das Entwurfsmuster "Prototype" mit Python
Lernen Sie das Entwurfsmuster "Builder" mit Python
Lernen Sie das Designmuster "Flyweight" in Python
Lernen Sie das Entwurfsmuster "Observer" in Python
Lernen Sie das Entwurfsmuster "Memento" mit Python
Lernen Sie das Entwurfsmuster "Proxy" in Python
Lernen Sie das Entwurfsmuster "Befehl" in Python
Lernen Sie das Entwurfsmuster "Bridge" mit Python
Lernen Sie das Entwurfsmuster "Mediator" mit Python
Lernen Sie das Designmuster "Decorator" mit Python
Lernen Sie das Entwurfsmuster "Iterator" mit Python
Lernen Sie das Entwurfsmuster "Strategie" mit Python
Lernen Sie das Entwurfsmuster "Composite" mit Python
Lernen Sie das Entwurfsmuster "State" in Python
Lernen Sie das Entwurfsmuster "Adapter" mit Python
Lernen Sie das Entwurfsmuster "Abstract Factory" mit Python
Lernen Sie das Entwurfsmuster "Vorlagenmethode" in Python
Lernen Sie das Entwurfsmuster "Factory Method" in Python
Lernen Sie das Entwurfsmuster "Chain of Responsibility" in Python
Besuchermuster in Python
Lernen Sie das Entwurfsmuster "Singleton" mit Python
Lernen Sie das Designmuster "Facade" mit Python
Implementieren Sie das Singleton-Muster in Python
Singleton-Muster in Python
Über das Besuchermuster
Finde Fehler in Python
Entwurfsmuster in Python: Einführung
Python Design Pattern - Template-Methode
Python im Browser: Brythons Empfehlung
Speichern Sie die Binärdatei in Python
Klicken Sie in Python auf die Sesami-API
Holen Sie sich den Desktop-Pfad in Python
Holen Sie sich den Skriptpfad in Python
Im Python-Befehl zeigt Python auf Python3.8
Klicken Sie auf die Web-API in Python
Ich habe die Warteschlange in Python geschrieben
Berechnen Sie den Vormonat in Python
Untersuchen Sie die Klasse eines Objekts mit Python
Holen Sie sich den Desktop-Pfad in Python
Holen Sie sich den Hostnamen in Python
Greifen Sie mit Python auf die Twitter-API zu
Der erste Schritt von Python Matplotlib
Ich habe den Stack in Python geschrieben
Beherrsche das schwache Ref-Modul in Python
Lernen Sie die Grundlagen von Python ① Grundlegende Anfänger
Versuchen Sie es mit der Wunderlist-API in Python
Überprüfen Sie das Verhalten des Zerstörers in Python
[Python Kivy] Über das Ändern des Designthemas
[Viererbande] Designmuster lernen --Besucher
Versuchen Sie, die Kraken-API mit Python zu verwenden
Lernen Sie die Grundlagen, während Sie Python-Variablen berühren
Schreiben Sie den Test in die Python-Dokumentzeichenfolge
Nehmen Sie die logische Summe von List in Python (Zip-Funktion)
GoF-Entwurfsmuster aus dem Problem 2. Struktur
Zeigen Sie Python 3 im Browser mit MAMP an
Tweet mit der Twitter-API in Python
Überprüfen Sie, ob die URL in Python vorhanden ist