Besuchermuster

In der objektorientierten Programmierung und Softwaretechnik ist das Besucherdesignmuster eine Weise, einen Algorithmus von einer Gegenstand-Struktur zu trennen, auf der es funktioniert. Ein praktisches Ergebnis dieser Trennung ist die Fähigkeit, neue Operationen zu vorhandenen Gegenstand-Strukturen hinzuzufügen, ohne jene Strukturen zu modifizieren. Es ist eine Weise, dem öffnen/schließen Grundsatz leicht zu folgen.

Hauptsächlich erlaubt der Besucher, neue virtuelle Funktionen zu einer Familie von Klassen hinzuzufügen, ohne die Klassen selbst zu modifizieren; statt dessen schafft man eine Besucherklasse, die alle passenden Spezialisierungen der virtuellen Funktion durchführt. Der Besucher nimmt die Beispiel-Verweisung, wie eingegeben, und führt die Absicht durch die doppelte Absendung durch.

Motivation

Denken Sie das Design eines 2. CAD-Systems. An seinem Kern gibt es mehrere Typen, um grundlegende geometrische Gestalten wie Kreise, Linien und Kreisbogen zu vertreten. Die entites werden in Schichten bestellt, und an der Oberseite vom Typ die Hierarchie ist die Zeichnung, die einfach eine Liste von Schichten plus einige zusätzliche Eigenschaften ist.

Eine grundsätzliche Operation auf dieser Typ-Hierarchie spart die Zeichnung zum Systemeingeborener-Dateiformat. Es scheint relativ fein, um lokal beizutragen, sparen Methoden zu allen Typen in der Hierarchie. Aber dann wollen wir auch im Stande sein, Zeichnungen zu anderen Dateiformaten zu sparen, und das Hinzufügen immer mehr füllen von Methoden, um in viele verschiedene Dateiformate zu sparen, bald die relativ reine geometrische Datenstruktur an, mit der wir aufgebrochen sind.

Eine naive Weise, das zu lösen, würde sein, getrennte Funktionen für jedes Dateiformat aufrechtzuerhalten. Solch ein, Funktion sparen, würde eine Zeichnung als Eingang nehmen, es überqueren und in dieses spezifische Dateiformat verschlüsseln. Aber wenn Sie das für mehrere verschiedene Formate tun, beginnen Sie bald, viel Verdoppelung zwischen den Funktionen, z.B viel Typ - wenn Behauptungen und überquerende Schleifen zu sehen. Ein anderes Problem mit dieser Annäherung besteht darin, wie leicht es eine bestimmte Gestalt in einem Retter verpassen soll.

Statt dessen konnten Sie das Besuchermuster anwenden. Das Besuchermuster fasst eine logische Operation auf der ganzen Hierarchie in eine einzelne Klasse kurz zusammen, die eine Methode pro Typ enthält. In unserem CAD-Beispiel spart jeder Funktion würde als eine getrennte Besucherunterklasse durchgeführt. Das würde alle Typ-Kontrollen und überquerende Verdoppelung entfernen. Es würde auch sich den Bearbeiter beklagen lassen, ob Sie eine Gestalt auslassen.

Details

Ein Benutzergegenstand erhält einen Zeigestock zu einem anderen Gegenstand, der einen Algorithmus durchführt.

Das erste wird die "Element-Klasse" und die Letzteren die "Besucherklasse benannt."

Die Idee ist, eine Struktur von Element-Klassen zu verwenden, von denen jede eine Methode hat, die einen Gegenstand für ein Argument nimmt. ist ein Protokoll (Schnittstelle in Java und C#) das Definieren einer Methode, die jede Element-Klasse anrufen kann. Die Methode einer Element-Klasse ruft die Methode zurück, die in der Durchführung des Besuchers definiert wird. Trennen Sie sich konkrete Klassen können dann geschrieben werden, um einige besondere Operationen, durch das Einführen dieser Operationen in ihren jeweiligen Methoden durchzuführen.

Von einer dieser Methoden eines Betons kann als eine Methode nicht von einer einzelnen Klasse, aber eher einer Methode eines Paares von Klassen gedacht werden: der konkrete Besucher und die besondere Element-Klasse. So täuscht das Besuchermuster doppelte Absendung in einer herkömmlichen einzelnen Absendung objektorientierte Sprache wie Java, Plausch und C ++ vor. Für eine Erklärung dessen, wie sich doppelte Absendung von der Funktionsüberbelastung unterscheidet, sieh, dass Doppelte Absendung mehr ist als Funktionsüberbelastung im doppelten Absendungsartikel. Auf der javanischen Sprache sind zwei Techniken dass Gebrauch-Nachdenken dokumentiert worden, um die Mechanik der doppelten Absendungssimulation im Besuchermuster zu vereinfachen. Mit den 1.2 JDK beginnend, akzeptiert das Bedürfnis nach "" Methode wurde durch das Hinzufügen "getMethod beseitigt ," der einem Gegenstand erlaubt zu kommen, wendet ein anderer Methoden mit spezifischen Rahmen ein. "Rufen " Methode an erlaubt diesen Methoden, genannt zu werden. Trotz des Vorteils mit einem reflektierenden Besucher gibt von der Codesyntax-Vereinfachung es sollte bemerkt werden, dass das reflektierende Besuchermuster unpassend sein kann, um über eine Vielzahl von Visitable-Gegenständen zu wiederholen - gibt es eine bedeutende Leistung oben zwischen zwei bis fünfzig Malen pro reflektierende Methode-Beschwörung im Vergleich zur regelmäßigen Methode-Beschwörung.

Das Besuchermuster gibt auch an, wie Wiederholung über die Gegenstand-Struktur vorkommt. In der einfachsten Version, wo jeder Algorithmus ebenso wiederholen muss, passiert die Methode eines Behälterelements, zusätzlich zum Wegrufen der Methode, auch den Gegenstand zur Methode aller seiner konstituierenden Kinderelemente.

Weil der Gegenstand eine Hauptfunktion hat (manifestiert in einer Mehrzahl von Spezialmethoden) und diese Funktion, die Dose genannt wird, als ein potenzieller Funktionsgegenstand sogleich identifiziert werden. Ebenfalls kann die Funktion als eine Funktionsapplikatur, ein mapper identifiziert werden, der weiß, wie man einen besonderen Typ des Gegenstands überquert und eine Funktion auf seine Elemente anwendet. Das Gegenstand-System des Lispelns mit seiner vielfachen Absendung ersetzt das Besuchermuster nicht, aber stellt bloß eine kürzere Durchführung davon zur Verfügung, in der das Muster fast verschwindet.

Javanisches Beispiel

Das folgende Beispiel ist auf der javanischen Programmiersprache und zeigt, wie der Inhalt eines Baums von Knoten (in diesem Fall das Beschreiben der Bestandteile eines Autos) gedruckt werden kann. Anstatt "Druck"-Methoden für jede Unterklasse (Rad, Motor, Körper und Auto) zu schaffen, führt eine einzelne Klasse (CarElementPrintVisitor) die erforderliche Druckhandlung durch. Weil verschiedene Unterklassen verlangen, dass ein bisschen verschiedene Handlungen richtig drucken, entsendet CarElementDoVisitor Handlungen, die auf der Klasse des dazu passierten Arguments gestützt sind.

Diagramm

Quelle

verbinden Sie CarElementVisitor {\

leerer Besuch (Radrad);

leerer Besuch (Motormotor);

leerer Besuch (Körperkörper);

leerer Besuch (Autoauto);

}\

verbinden Sie CarElement {\

Leere akzeptiert (Besucher von CarElementVisitor);//müssen CarElements zur Verfügung stellen akzeptieren .

}\

Klassenrad führt CarElement {\durch

privater Schnur-Name;

öffentliches Rad (Schnur-Name) {\

this.name = Name;

}\

öffentliche Schnur getName {\

geben Sie this.name zurück;

}\

öffentliche Leere akzeptiert (Besucher von CarElementVisitor) {\

/ *

* überreitet Wheel.accept (CarElementVisitor) CarElement.accept (CarElementVisitor), so der Anruf

*, um zu akzeptieren, wird in der Durchlaufzeit gebunden. Das kann als die erste Absendung betrachtet werden.

* Die Entscheidung, CarElementVisitor.visit (Rad) jedoch, aber nicht der andere 'Besuch' zu nennen

* Methoden in CarElementVisitor, kann während der Übersetzungszeit gemacht werden, da 'das' daran bekannt ist, kompilieren

* Zeit, um ein Rad zu sein. Außerdem überreitet jede Unterklasse von CarElementVisitor den Besuch (Rad),

*, der eine andere Entscheidung ist, die in der Durchlaufzeit gemacht wird. Das kann als die zweite Absendung betrachtet werden.

*/

visitor.visit (das);

}\}\

Klassenmotor führt CarElement {\durch

öffentliche Leere akzeptiert (Besucher von CarElementVisitor) {\

visitor.visit (das);

}\}\

Klassenkörper führt CarElement {\durch

öffentliche Leere akzeptiert (Besucher von CarElementVisitor) {\ visitor.visit (das); }\}\

Klassenauto führt CarElement {\durch

CarElement [] Elemente;

öffentliches Auto {\

//schaffen Sie neue Reihe von Elementen

this.elements = neuer CarElement [] {neues Rad ("Vorderseite ist" abgereist),

neues Rad ("Vorderrecht"), neues Rad ("zurück verlassen"),

neues Rad ("zurück Recht"), neuer Körper , neuer Motor };

}\

öffentliche Leere akzeptiert (Besucher von CarElementVisitor) {\

für (CarElement elem: Elemente) {\

elem.accept (Besucher);

}\

visitor.visit (das)

; }\}\

Klasse CarElementPrintVisitor führt CarElementVisitor {\durch

öffentlicher leerer Besuch (Radrad) {

System.out.println (""+ wheel.getName +" Rad") Besuchend;

}\

öffentlicher leerer Besuch (Motormotor) {\

System.out.println ("Motor" besuchend);

}\

öffentlicher leerer Besuch (Körperkörper) {\

System.out.println ("Körper" besuchend);

}\

öffentlicher leerer Besuch (Autoauto) {

System.out.println ("Auto" besuchend);

}\}\

Klasse CarElementDoVisitor führt CarElementVisitor {\durch

öffentlicher leerer Besuch (Radrad) {\

System.out.println ("Mein "+ wheel.getName +" Rad") tretend;

}\ öffentlicher leerer Besuch (Motormotor) {\

System.out.println ("Meinen Motor" anfangend);

}\ öffentlicher leerer Besuch (Körperkörper) {\

System.out.println ("Meinen Körper" bewegend);

}\

öffentlicher leerer Besuch (Autoauto) {\

System.out.println ("Mein Auto" anfangend);

}\}\

öffentliche Klasse VisitorDemo {\

statische öffentliche leere Hauptsache (Schnur [] args) {\

Autoauto = neues Auto ;

car.accept (neuer CarElementPrintVisitor );

car.accept (neuer CarElementDoVisitor );

}\}\

</Quelle>

Referenzen: Eine flexiblere Annäherung an dieses Muster soll eine Streifband-Klasse schaffen, die die Schnittstelle durchführt, die die akzeptieren Methode definiert. Das Streifband enthält eine Verweisung, die zu CarElement hinweist, der durch den Konstrukteur initialisiert werden konnte. Diese Annäherung vermeidet, eine Schnittstelle auf jedem Element durchführen zu müssen. [sieh Artikel des Artikels Java Tip 98 unten]

Produktion

Der Besuch der Vorderseite hat Rad verlassen

Der Besuch richtigen Vorderrades

Der Besuch zurück verlassen Rad

Der Besuch zurück richtigen Rades

Besuch des Körpers

Besuch des Motors

Besuch des Autos

Das Treten meiner Vorderseite hat Rad verlassen

Das Treten meines richtigen Vorderrades

Das Treten meines Rückens hat Rad verlassen

Das Treten meines Zurückrecht-Rades

Das Bewegen meines Körpers

Das Starten meines Motors

Das Starten meines Autos

</pre>

Lispeln-Beispiel

Quelle

((Elemente: initarg: Elemente)))

(defclass Autoteil

((Name: initarg: Name: initform"

(defmethod Druckgegenstand ((p Autoteil) Strom)

(Druckgegenstand (Ablagefach-Wert p 'Name) Strom))

(defclass Rad (Autoteil) )

(defclass Körper (Autoteil) )

(defclass Motor (Autoteil) )

(defgeneric Überquerung (fungieren Gegenstand-anderer-Gegenstand))

(defmethod Überquerung (Funktion (ein Auto) anderer-Gegenstand)

(mit den Ablagefächern (Elemente) ein

(dolist (e Elemente)

(funcall fungieren e anderer-Gegenstand))))

; tun Sie - etwas Visitationen

; fangen Sie den ganzen

(defmethod tun - etwas (wenden Sie anderen-Gegenstand ein)

(Format t "weiß nicht, wie ~s und ~s ~ %" Gegenstand-anderer-Gegenstand aufeinander wirken sollten))

; Visitation, die Rad und ganze Zahl einschließt

(defmethod tun - etwas ((wenden Sie Rad ein) (ganze Zahl des anderen-Gegenstands))

(Format t "das Treten des Rades ~s ~s Zeiten ~ %" wendet anderen-Gegenstand ein))

; Visitation, die Rad und Symbol einschließt

(defmethod tun - etwas ((wenden Sie Rad ein) (Symbol des anderen-Gegenstands))

(Format t "das Treten des Rades ~s symbolisch mit dem Symbol ~s ~ %" wendet anderen-Gegenstand ein))

(defmethod tun - etwas ((wenden Sie Motor ein) (ganze Zahl des anderen-Gegenstands))

(Format t "Startmotor ~s ~s Zeiten ~ %" wendet anderen-Gegenstand ein))

(defmethod tun - etwas ((wenden Sie Motor ein) (Symbol des anderen-Gegenstands))

(Format t "Startmotor ~s symbolisch mit dem Symbol ~s ~ %" wendet anderen-Gegenstand ein))

(lassen Sie (((Machen-Beispiel 'Auto

:elements` ((Machen-Beispiel 'Rad: Nennen Sie "Vorder-linkes Rad")

(Machen-Beispiel 'Rad: Nennen Sie "Vorder-richtiges Rad")

(Machen-Beispiel 'Rad: Nennen Sie "hinteres richtiges Rad")

(Machen-Beispiel 'Rad: Nennen Sie "hinteres richtiges Rad")

(Machen-Beispiel 'Körper: Nennen Sie "Körper")

(Machen-Beispiel 'Motor: Nennen Sie "Motor")))))

;; überqueren Sie, um Elemente zu drucken

;; Strom spielt *standard-output* die Rolle des anderen-Gegenstands hier

(überqueren Sie # 'print *standard-output *)

(terpri);; drucken Sie newline

;; Überquerung mit dem willkürlichen Zusammenhang von anderem Gegenstand

(überqueren Sie # 'do-etwas 42)

;; Überquerung mit dem willkürlichen Zusammenhang von anderem Gegenstand

(überqueren Sie # 'do-etwas ein 'Alphabet)) </Quelle>

Produktion

"Vorder-richtiges Rad"

"hinteres richtiges Rad"

"hinteres richtiges Rad"

"Körper"

"Motor"

das Treten des Rades "Vorder-linkes Rad" 42mal

das Treten des Rades "Vorder-richtiges Rad" 42mal

das Treten des Rades "hinteres richtiges Rad" 42mal

das Treten des Rades "hinteres richtiges Rad" 42mal

wissen Sie nicht, wie "Körper" und 42 aufeinander wirken sollte

Startmotor "Motor" 42mal

das Treten des Rades "Vorder-linkes Rad" symbolisch mit dem Symbol-Abc

das Treten des Rades "Vorder-richtiges Rad" symbolisch mit dem Symbol-Abc

das Treten des Rades "hinteres richtiges Rad" symbolisch mit dem Symbol-Abc

das Treten des Rades "hinteres richtiges Rad" symbolisch mit dem Symbol-Abc

wissen Sie nicht, wie "Körper" und Abc aufeinander wirken sollten

Startmotor "Motor" symbolisch mit dem Symbol-Abc </pre>

Zeichen

Der Parameter ist darin überflüssig. Der Grund besteht darin, dass es möglich ist, eine anonyme Funktion zu verwenden, die die gewünschte Zielmethode mit einem lexikalisch gewonnenen Gegenstand nennt:

(mit den Ablagefächern (Elemente) ein (dolist (e Elemente)

(funcall fungieren e))));; von hier auch

;...

;; alternativer Weg zur Drucküberquerung

(Überquerung (Lambda (o) (drucken o *standard-output *)))

;; alternative Weise - etwas mit zu tun

;; Elemente von a und ganzer Zahl 42

(Überquerung (Lambda (o) (tun - etwas o 42)), a) </Quelle>

Jetzt kommt die vielfache Absendung im Anruf vor, der vom Körper der anonymen Funktion ausgegeben ist, und ist so gerade eine kartografisch darstellende Funktion, die eine Funktionsanwendung über die Elemente eines Gegenstands verteilt. So verschwinden alle Spuren des Besuchermusters abgesehen von der kartografisch darstellenden Funktion, in der es keine Beweise von zwei Gegenständen gibt, die beteiligen werden. Alle Kenntnisse, dort zwei Gegenstände und eine Absendung auf ihren Typen zu sein, sind in der Lambda-Funktion.

Staat

Beiseite von der sich potenziell verbessernden Trennung von Sorgen hat das Besuchermuster einen zusätzlichen Vorteil einfach das Benennen einer polymorphen Methode: Ein Besuchergegenstand kann Staat haben. Das ist in vielen Fällen äußerst nützlich, wo die auf dem Gegenstand durchgeführte Handlung vorherig solche Handlungen abhängt.

Ein Beispiel davon ist ein hübscher Drucker in einer Programmiersprache-Durchführung (wie ein Bearbeiter oder Dolmetscher). Solch ein Gegenstand des hübschen Druckers (durchgeführt als ein Besucher, in diesem Beispiel), wird Knoten in einer Datenstruktur besuchen, die ein grammatisch analysiertes und bearbeitetes Programm vertritt. Der hübsche Drucker wird dann eine Textdarstellung des Programm-Baums erzeugen. Um die Darstellung menschlich-lesbar zu machen, sollte der hübsche Drucker Programm-Behauptungen und Ausdrücke richtig eindrücken. Das aktuelle Einrückungsniveau kann dann vom Besucher als sein Staat verfolgt werden, richtig encapsulation geltend, wohingegen in einer einfachen polymorphen Methode-Beschwörung das Einrückungsniveau als ein Parameter würde ausgestellt werden müssen und sich der Anrufer auf die Methode-Durchführung verlassen würde, um diesen Parameter richtig zu verwenden und fortzupflanzen.

Siehe auch

  • Doppelte und vielfache Absendung
  • Hierarchisches Besuchermuster
  • Funktionsgegenstand

Links


1524 / 1518
Impressum & Datenschutz