Besuchermuster in Python

[AST] (http://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%A7%8B%E6%96%87%E6%9C%A8) wird untersucht [Besucher Muster] (http://ja.wikipedia.org/wiki/Visitor_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3) kam heraus. Was hat Sie glücklich gemacht, als Sie das Besuchermuster verwendet haben? Ich kannte die Grundlagen nicht und habe sie überprüft: Schweiß:

Wikipedia hat ein Java-Codebeispiel, also habe ich es in Python3 umgeschrieben. Anfangs habe ich den japanischen Code portiert, während ich mir das Beispiel angesehen habe, und wenn ich dachte, dass es sich um ein halbfertiges Beispiel handelt, das englische Besuchermuster ) Wurde in ein prägnanteres Codebeispiel geändert. Es scheint besser, diese Seite auf Englisch zu betrachten.

Da Python keine Schnittstelle hat, verwende ich den Dekorator @ abstractmethod des Moduls abc. Abgesehen davon gilt das Modul * abc * nur für Instanzen von Klassen, aber * zope.interface * eignet sich hervorragend für Klassen, Objekte, Module usw.

Ruhige Gesprächspause. Schauen wir uns das Muster an, während wir uns den Code ansehen.

3.4


# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod

class ICarElementVisitor(metaclass=ABCMeta):
    """
    Interface like in Python
    """
    @abstractmethod
    def visit_Wheel(self, wheel): pass

    @abstractmethod
    def visit_Engine(self, engine): pass

    @abstractmethod
    def visit_Body(self, body): pass

    @abstractmethod
    def visit_Car(self, car): pass

class ICarElement(metaclass=ABCMeta):
    """
    Interface like in Python
    """
    @abstractmethod
    def accept(self, visitor): pass

class Wheel(ICarElement):
    def __init__(self, name):
        self.name = name

    def accept(self, visitor):
        visitor.visit_Wheel(self)

class Engine(ICarElement):
    def accept(self, visitor):
        visitor.visit_Engine(self)

class Body(ICarElement):
    def accept(self, visitor):
        visitor.visit_Body(self)

class Car(ICarElement):

    def __init__(self):
        self.elements = [
            Wheel('front left'), Wheel('front right'),
            Wheel('back left'), Wheel('back right'),
            Body(), Engine(),
        ]

    def accept(self, visitor):
        for elem in self.elements:
            elem.accept(visitor)
        visitor.visit_Car(self)

class PrintVisitor(ICarElementVisitor):
    def visit_Wheel(self, wheel):
        print('Visiting {} wheel'.format(wheel.name))

    def visit_Engine(self, engine):
        print('Visiting engine')

    def visit_Body(self, body):
        print('Visiting body')

    def visit_Car(self, car):
        print('Visiting car')

class DoVisitor(ICarElementVisitor):
    def visit_Wheel(self, wheel):
        print('Kicking my {} wheel'.format(wheel.name))

    def visit_Engine(self, engine):
        print('Starting my engine')

    def visit_Body(self, body):
        print('Moving my body')

    def visit_Car(self, car):
        print('Starting my car')

def main():
    """
    >>> main()
    Visiting front left wheel
    Visiting front right wheel
    Visiting back left wheel
    Visiting back right wheel
    Visiting body
    Visiting engine
    Visiting car
    --------------------------------
    Kicking my front left wheel
    Kicking my front right wheel
    Kicking my back left wheel
    Kicking my back right wheel
    Moving my body
    Starting my engine
    Starting my car
    """
    car = Car()
    car.accept(PrintVisitor())
    print('-' * 32)
    car.accept(DoVisitor())

Wenn Sie den Java-Code so portieren, wie er ist, sieht er folgendermaßen aus. Da es sich jedoch um Python handelt, sollten Sie ihn etwas weiter lockern.

--- visitor.py	2015-02-17 18:43:53.000000000 +0900
+++ visitor-generic.py	2015-02-17 18:46:24.000000000 +0900
@@ -6,16 +6,8 @@
     Interface like in Python
     """
     @abstractmethod
-    def visit_Wheel(self, wheel): pass
-
-    @abstractmethod
-    def visit_Engine(self, engine): pass
-
-    @abstractmethod
-    def visit_Body(self, body): pass
-
-    @abstractmethod
-    def visit_Car(self, car): pass
+    def visit(self, obj):
+        getattr(self, 'visit_' + obj.__class__.__name__)(obj)
 
 class ICarElement(metaclass=ABCMeta):
     """
@@ -29,15 +21,15 @@
         self.name = name
 
     def accept(self, visitor):
-        visitor.visit_Wheel(self)
+        visitor.visit(self)
 
 class Engine(ICarElement):
     def accept(self, visitor):
-        visitor.visit_Engine(self)
+        visitor.visit(self)
 
 class Body(ICarElement):
     def accept(self, visitor):
-        visitor.visit_Body(self)
+        visitor.visit(self)
 
 class Car(ICarElement):
 
@@ -51,9 +43,12 @@
     def accept(self, visitor):
         for elem in self.elements:
             elem.accept(visitor)
-        visitor.visit_Car(self)
+        visitor.visit(self)
 
 class PrintVisitor(ICarElementVisitor):
+    def visit(self, obj):
+        getattr(self, 'visit_' + obj.__class__.__name__)(obj)
+
     def visit_Wheel(self, wheel):
         print('Visiting {} wheel'.format(wheel.name))
 
@@ -67,6 +62,9 @@
         print('Visiting car')
 
 class DoVisitor(ICarElementVisitor):
+    def visit(self, obj):
+        super().visit(obj)
+

Um die Änderungen kurz zu erläutern, verwenden wir Reflection, um eine Standardimplementierung für etwas Interface-ähnliches zu definieren.

3.4


class ICarElementVisitor(metaclass=ABCMeta):
    """
    Interface like in Python
    """
    @abstractmethod
    def visit(self, obj):
        getattr(self, 'visit_' + obj.__class__.__name__)(obj)

3.4


class Engine(ICarElement):
    def accept(self, visitor):
        visitor.visit(self)

Die Besucher-Unterklasse kann direkt eine Implementierung von "visit ()" wie "PrintVisitor" definieren oder die Standardimplementierung einer abstrakten Klasse (Schnittstelle) wie "DoVisitor" verwenden.

3.4


class PrintVisitor(ICarElementVisitor):
    def visit(self, obj):
        getattr(self, 'visit_' + obj.__class__.__name__)(obj)
    ...

class DoVisitor(ICarElementVisitor):
    def visit(self, obj):
        super().visit(obj)
    ...

Das Besuchermuster übergibt das Visitor-Objekt an die Methode "accept ()" und ruft die darin enthaltene Methode "visit.visit (self)" auf (Double Dispatch). ). In diesem Beispiel wird auch die Methode "elem.accept (Besucher)" jedes Elementobjekts in "car.accept (Besucher)" aufgerufen.

Einer der Vorteile besteht darin, dass Sie über mehrere Elementobjekte hinweg arbeiten können (* traverse *), sodass Sie den Code oder die Datenstruktur vorhandener Objekte nicht ändern müssen, wenn Sie neue Operationen hinzufügen. Dies führt zu Bedenken (http://en.wikipedia.org/wiki/Separation_of_concerns).

Wenn Sie beispielsweise überlegen, eine Operation namens Bremsen hinzuzufügen,

+class Brake(ICarElement):
+    def accept(self, visitor):
+        visitor.visit(self)
+
 class Car(ICarElement):
 
     def __init__(self):
         self.elements = [
             Wheel('front left'), Wheel('front right'),
             Wheel('back left'), Wheel('back right'),
-            Body(), Engine(),
+            Body(), Engine(), Brake(),
         ]
@@ -55,6 +59,9 @@
     def visit_Engine(self, engine):
         print('Visiting engine')
 
+    def visit_Brake(self, engine):
+        print('Visiting brake')
+        

Das ist alles was Sie tun müssen.

Darüber hinaus wird das "Besucher" -Objekt als leistungsfähiger als die * polymorphe * Methode beschrieben, da es auch Zustände haben kann.

In diesem Beispiel wird der Status nicht speziell verwaltet, aber es kann gesagt werden, dass es einfach ist, die Reihenfolge aufzuzeichnen, in der sie aufgerufen werden, oder ein Flag zu setzen, wenn eine Operation ausgeführt wird.

Nach dem Schreiben und erneuten Überprüfen [Vergleich von Besuchermuster und Ententypisierung] Laut (http://d.hatena.ne.jp/podhmo/20101127/1290845198), [Expert Python Programming](http://ascii.asciimw.jp/books/books/detail/978-4-04- War es in 868629-7.shtml aufgeführt)? Es war vor vielen Jahren, und ich erinnere mich, dass ich an einer Lesung teilgenommen und dort darüber gesprochen habe, aber ich habe mich überhaupt nicht an den Code erinnert.

Recommended Posts

Besuchermuster in Python
Singleton-Muster in Python
Lernen Sie das Entwurfsmuster "Besucher" mit Python
Implementieren Sie das Singleton-Muster in Python
Quadtree in Python --2
Python in der Optimierung
CURL in Python
Metaprogrammierung mit Python
Python 3.3 mit Anaconda
Geokodierung in Python
SendKeys in Python
Metaanalyse in Python
Unittest in Python
Epoche in Python
Zwietracht in Python
Deutsch in Python
DCI in Python
Quicksort in Python
nCr in Python
N-Gramm in Python
Programmieren mit Python
Plink in Python
Konstante in Python
FizzBuzz in Python
SQLite in Python
Schritt AIC in Python
LINE-Bot [0] in Python
CSV in Python
Reverse Assembler mit Python
Reflexion in Python
Konstante in Python
nCr in Python.
Format in Python
Scons in Python 3
Puyopuyo in Python
Python in Virtualenv
PPAP in Python
Quad-Tree in Python
Reflexion in Python
Chemie mit Python
Hashbar in Python
DirectLiNGAM in Python
LiNGAM in Python
In Python reduzieren
In Python flach drücken
Lernen Sie das Entwurfsmuster "Prototype" mit Python
Lernen Sie das Entwurfsmuster "Builder" mit Python
Lernen Sie das Entwurfsmuster "Observer" in 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
Sortierte Liste in Python