Besucher - an der HTWG Konstanz

Werbung
Robert Walter
MSI 3
EMFW WS 08/09
Besucher Muster (Visitor)
Ein objektbasiertes Verhaltensmuster
15.01.09
Beschreibung I
• Klassifizierung:
– Objektbasiertes Verhaltensmuster
• Zweck: – Kapsle eine auf den Elementen einer Objektstruktur auszuführende Operation als ein Objekt
• Motivation: – Übersetzer, der auf Elemente seiner Sprache verschiedene Operationen ausführen muss:
• Typisierung, Code‐Generierung, Pretty‐Printing, etc.
– Unterschiedliche Elemente verlangen unterschiedliche Implementierungen der Operationen
• => Jedes Element (jede Klasse der Baumstruktur) implementiert jede Operation
15.01.2009
Robert Walter ‐ MSI 3
2
/ 46
Beschreibung II
• Fortsetzung Motivation
Knoten
+PruefeTypisierung()
+GeneriereCode()
+PrettyPrint()
VariablenRefKnoten
ZuweisungsKnoten
MethDeklKnoten
+PruefeTypisierung()
+GeneriereCode()
+PrettyPrint()
+PruefeTypisierung()
+GeneriereCode()
+PrettyPrint()
+PruefeTypisierung()
+GeneriereCode()
+PrettyPrint()
– Verwirrende Struktur • z.B. Pretty‐Printing & Typisierung vermischt
– Hinzufügen von neuen Operationen sehr aufwendig
15.01.2009
Robert Walter ‐ MSI 3
3
/ 46
Beschreibung III
• Fortsetzung Motivation
– Verbesserungen
• Operationen sind vom Klassenbaum unabhängig
• Knotenklassen unabhängig von den auf sie anzuwendenden
Operationen
– Realisierung
• Zusammenfassen verwandter Operationen jeder Klasse in separatem Objekt => Besucher
• Bei Traversierung erhalten Knoten Besucher als Parameter übergeben
• Akzeptiert ein Knoten den übergebenen Besucher, ruft er eine entsprechende Bearbeitungs‐Operation des Besuchers auf und übergibt wiederum sich selbst als Parameter
15.01.2009
Robert Walter ‐ MSI 3
4
/ 46
Beschreibung IV
Besucher
+Besuche(ZuweisungsKnoten)
+Besuche(VariablenRefKnoten)
+Besuche(MethDeklKnoten)
TypPruefungsBesucher
+Besuche(ZuweisungsKnoten k)
+Besuche(VariablenRefKnoten k)
+Besuche(MethDeklKnoten k)
CodeGenerierungsBesucher
+Besuche(ZuweisungsKnoten k)
+Besuche(VariablenRefKnoten k)
+Besuche(MethDeklKnoten k)
Programm
PrettyPrintBe...
+Besuche(Zuwei...
+Besuche(Varia...
+Besuche(MethD...
Knoten
+NimmEntgegen(Besucher)
VariablenRefKnoten
ZuweisungsKnoten
MethDeklKnoten
+NimmEntgegen(Besucher b)
+NimmEntgegen(Besucher b)
+NimmEntgegen(Besucher b)
b->Besuche(this);
15.01.2009
Robert Walter ‐ MSI 3
b->Besuche(this);
b->Besuche(this);
5
/ 46
Anwendbarkeit
• Verwenden, wenn
– man klassenabhängige Operationen auf Objekte großer Strukturen mit unterschiedlicher Schnittstelle ausführen will
– man unterschiedliche Operationen auf viele Objekte von den Objekten trennen will, um „Objektverschmutzung“ zu vermeiden; Operations‐Kapselung ermöglicht Verteilung der Aufgaben auf mehrere Anwendungen
– die Klassen der Struktur sich nur selten ändern, die darauf ausgeführten Operationen aber oft; Strukturänderungen erfordern eine Neudefinition der Besucherschnittstellen!
15.01.2009
Robert Walter ‐ MSI 3
6
/ 46
Teilnehmer I
Klient
Besucher
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
KonkreterBesucher2
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
ObjektStruktur
KonkreterBesucher2
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
Element
+NimmEntgegen(Besucher)
KonkretesElementA
KonkretesElementB
+NimmEntgegen(Besucher b)
+OperationA()
+NimmEntgegen(Besucher b)
+OperationB()
b->Besuche(this);
15.01.2009
Robert Walter ‐ MSI 3
b->Besuche(this);
7
/ 46
Teilnehmer II
Besucher
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
KonkreterBesucher1
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
KonkreterBesucher2
+Besuche(KonkretesElementA)
+Besuche(KonkretesElementB)
• KonkreterBesucher
– implementiert „Besucher‐Operationen“
• Besucher‐Operation stellt Fragment des Algorithmus der entsprechenden Struktur‐Klasse dar
15.01.2009
Robert Walter ‐ MSI 3
8
/ 46
Teilnehmer III
Element
+NimmEntgegen(Besucher)
KonkretesElementA
KonkretesElementB
+NimmEntgegen(Besucher b)
+OperationA()
+NimmEntgegen(Besucher b)
+OperationB()
b->Besuche(this);
b->Besuche(this);
• Element
– definiert eine „NimmEntgegen“‐Operation, die einen Besucher als Argument erwartet
• Konkretes Element
– implementiert eine „NimmEntgegen“‐Operation und startet den Besuchsvorgang
15.01.2009
Robert Walter ‐ MSI 3
9
/ 46
Konsequenzen
•
•
Besucher machen das Hinzufügen neuer Operationen einfach
Zusammenführung verwandter Operationen – Trennung von den Operationen, die nichts mit der Besucheraufgabe zu tun haben
•
•
Änderungen der Struktur auf Klassenebene ist schwer
Klassenhierarchie übergreifender Besucher
– im Vgl. zum Iterator müssen die besuchten Objekte nicht über gemeinsame Oberklasse verfügen
•
Ansammeln von Zustandsinformationen
– Anstatt Parameter‐Forwarding bei Traversierung oder globaler Variablen
•
Aufbrechung der Kapselung
– Besuchte Elemente brauchen starke Schnittstellen (enge Zusammenarbeit zwischen Objekt und Besucher)
=> Objekt muss eventuell Schnittstellen auf seinen internen Zustand bereitstellen
15.01.2009
Robert Walter ‐ MSI 3
10
/ 46
Beispiele I
• Besucher‐Muster kann gut in Frameworks integriert werden, wie das JDT (Java Development Toolkit) zeigt
– JDT stellt AST (Konkrete Objektstruktur) zu Java‐
Programm bereit
– Außerdem auch Besucher‐Schnittstelle
• Beispiel zeigt, wie ein Java‐AST in eine neue abstrakte Syntax überführt wird
Java‐AST
Neue Graph‐Struktur
CompilationUnit
15.01.2009
Robert Walter ‐ MSI 3
11
/ 46
Beispiele II
• JDT stellt bereit
– Objektstruktur (über Wurzel vom Typ CompilationUnit)
– Besucher‐Schnittstelle (ASTVisitor)
• diese muss implementiert werden (=> ASTVisitorImpl2)
• Traversierung (Anwendungssteuerung) liegt bei Framework
• Visitor kann natürlich auch „von Hand“ implementiert werden...
15.01.2009
Robert Walter ‐ MSI 3
12
/ 46
Beispiele III
interface Visitor {
void visit (Wheel wheel);
void visit (Engine engine);
void visit (Body body);
void visitCar (Car car);
}
15.01.2009
Robert Walter ‐ MSI 3
class PrintVisitor implements Visitor {
public void visit (Wheel wheel) {
println („\tVisiting "+ wheel.getName() + " wheel");
}
public void visit (Engine engine) {
println („\tVisiting engine");
}
public void visit (Body body) {
println („\tVisiting body");
}
public void visitCar (Car car) {
println ("\nVisiting car");
for (CarElement element : car.getElements()) {
element.accept(this);
}
println("Visited car");
}
}
13
/ 46
Beispiele III
interface CarElement {
public void accept (Visitor visitor);
}
class Body implements CarElement{
public void accept (Visitor visitor) {
visitor.visit (this);
}
}
class Engine implements CarElement{
public void accept (Visitor visitor) {
visitor.visit (this);
}
}
class Wheel implements CarElement {
private String name;
Wheel (String name) {
this.name = name;
}
String getName() { return name; }
public void accept (Visitor visitor) {
visitor.visit (this);
}
}
class Car {
CarElement[] elements;
public CarElement [] getElements(){
return elements.clone();
}
public Car() {
this.elements = new CarElement[]
{ new Wheel("front left"), new Wheel("front right"),
new Wheel("back left") , new Wheel("back right"),
new Body(), new Engine() };
}
}
15.01.2009
Robert Walter ‐ MSI 3
14
/ 46
Beispiele IV
public class VisitorDemo {
static public void main (String[] args){
Car car = new Car();
Visitor printVisitor = new PrintVisitor();
printVisitor.visitCar (car);
}
}
• Ausgabe:
Visiting Car
Visiting front left wheel
Visiting front right wheel
Visiting back left wheel
Visiting back right wheel
Visiting body
Visiting engine
Visited car
15.01.2009
Robert Walter ‐ MSI 3
15
/ 46
Herunterladen