Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern,...

38
Programmieren in Java Vorlesung 06: Das Visitor Pattern Prof. Dr. Peter Thiemann (vertreten durch Luminous Fennell) Albert-Ludwigs-Universit¨ at Freiburg, Germany SS 2015 Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 1 / 25

Transcript of Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern,...

Page 1: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Programmieren in JavaVorlesung 06: Das Visitor Pattern

Prof. Dr. Peter Thiemann(vertreten durch Luminous Fennell)

Albert-Ludwigs-Universitat Freiburg, Germany

SS 2015

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 1 / 25

Page 2: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Executive Summary — Visitor Pattern

I Design-Pattern, dass bei rekursiven Klassen Verwendung findetI Es erlaubt einfaches und modulares Hinzufugen von Operationen

fur ein DatenmodellI Erweitern des Datenmodells ist schwierigerI Gegenspieler zum Composite Pattern,

wo Operationen schwerer hinzuzufugen sind.

I Geeignete Modelle sind z.B.I Arithmetische/Boolesche/. . . AusdruckeI Reprasentation von Programmen einer Programmiersprache

(z.B. beim Compilerbau)

I Operationen werden als Subklassen eines Visitor-Interfaces perFallunterscheidung implementiert

I Es genugt eine Methode im Datenmodell (accept)um eine Vielzahl von Visitor-basierten Operationen zu Unterstutzen

I Laufendes Beispiel heute: Arithmetische Ausdrucke

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 2 / 25

Page 3: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Inhalt

Wiederholung: Arithmetische Ausdrucke

Einschub: Static Imports

Hinzufugen weiterer Operationen

Visitors

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 3 / 25

Page 4: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Wiederholung: Arithmetische Ausdrucke

Wiederholung: Arithmetische Ausdrucke

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 4 / 25

Page 5: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Wiederholung: Arithmetische Ausdrucke

Arithmetische Ausdrucke

DatenmodellEin arithmetischer Ausdruck hat eine der folgenden Formen:

I eine Konstante (eine ganze Zahl),Beispiele: 0, 51, −42

I eine Summe von zwei arithmetischen Ausdrucken,Beispiele: 3+4, 17+4, 17+ (2+2)

I ein Produkt von zwei arithmetischen Ausdrucken,Beispiele: 3∗4, 2 ∗ (17+4), (2 ∗ 3) ∗ 4

Operationen fur arithmetische Ausdrucke

I Berechnung des Werts: eval(3 + 4) 7

I Berechnung seiner Große: size(3 + 4) 3

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 5 / 25

Page 6: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Wiederholung: Arithmetische Ausdrucke

Datenmodell

Arithmetische Ausdrucke sindrekursive, unveranderliche Datenstrukturen

I Basisfall: Konstanten

I Rekursive Falle: Addition und Produkt

I Hier: Zugriff auf Bestandteile durch public final Felder.

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 6 / 25

Page 7: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Wiederholung: Arithmetische Ausdrucke

OperationenModellierung mit Composite Pattern

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 7 / 25

Page 8: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Einschub: Static Imports

Static Imports

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 8 / 25

Page 9: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Einschub: Static Imports

Erzeugen von Beispiel-AusdruckenMit Java Konstruktoren

1 @Test2 public void testEval() {3 // (42 + (5 ∗ 4)) ∗ (2 + 1)4 IExpr e = new Product(new Add(new Const(42), new Product(new Const(5),5 new Const(4))), new Add(new Const(2), new Const(1)));6 assertEquals(168, e.eval());7 }

Java’s Syntax fur Konstruktoraufrufe ist fur dasErstellen verschachtelter Strukturen sehr unleserlich.

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 9 / 25

Page 10: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Einschub: Static Imports

Erzeugen von Beispiel-AusdruckenMit statischen Factory-Methoden

1 @Test2 public void testEvalStatic() {3 // (42 + (5 ∗ 4)) ∗ (2 + 1)4 IExpr e = product(add(42, product(5, 4)), add(2, 1));5 assertEquals(168, e.eval());6 }

I Die statischen Methoden product und add sind statische Methodenaus einer Klasse Expressions.

I Durch statische Imports kann der Klassenname beim Aufrufweggelassen werden

import composite.Expressions;

normaler import, erlaubt: Expressions.add(42, 5);

import static composite.Expressions.∗;

statischer import, erlaubt: add(42,5)

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 10 / 25

Page 11: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Einschub: Static Imports

Erzeugen von Beispiel-AusdruckenMit statischen Factory-Methoden

1 @Test2 public void testEvalStatic() {3 // (42 + (5 ∗ 4)) ∗ (2 + 1)4 IExpr e = product(add(42, product(5, 4)), add(2, 1));5 assertEquals(168, e.eval());6 }

I Die statischen Methoden product und add sind statische Methodenaus einer Klasse Expressions.

I Durch statische Imports kann der Klassenname beim Aufrufweggelassen werden

import composite.Expressions;

normaler import, erlaubt: Expressions.add(42, 5);

import static composite.Expressions.∗;

statischer import, erlaubt: add(42,5)

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 10 / 25

Page 12: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Hinzufugen weiterer Operationen

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 11 / 25

Page 13: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Weitere Operationen fur Arithmethische Ausdrucke

I prettyprint(IExpr)prettyprint(add(add(0, 5), 8)) “((0 + 5) + 8)”

I depth(IExpr)depth(add(add(0, 5), 8)) 3

I simplify()simplify(add(add(0, 5), 8)) add(5, 8)

I Bisher: Modellierung mit Composite Pattern

I Problem: Composite Pattern erfordert beim Hinzufugendie Modifikation aller Ausdruck-Klassen

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 12 / 25

Page 14: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Weitere Operationen fur Arithmethische Ausdrucke

I prettyprint(IExpr)prettyprint(add(add(0, 5), 8)) “((0 + 5) + 8)”

I depth(IExpr)depth(add(add(0, 5), 8)) 3

I simplify()simplify(add(add(0, 5), 8)) add(5, 8)

I Bisher: Modellierung mit Composite Pattern

I Problem: Composite Pattern erfordert beim Hinzufugendie Modifikation aller Ausdruck-Klassen

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 12 / 25

Page 15: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Weitere Operationen fur Arithmethische Ausdrucke

I prettyprint(IExpr)prettyprint(add(add(0, 5), 8)) “((0 + 5) + 8)”

I depth(IExpr)depth(add(add(0, 5), 8)) 3

I simplify()simplify(add(add(0, 5), 8)) add(5, 8)

I Bisher: Modellierung mit Composite Pattern

I Problem: Composite Pattern erfordert beim Hinzufugendie Modifikation aller Ausdruck-Klassen

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 12 / 25

Page 16: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Weitere Operationen fur Arithmethische Ausdrucke

I prettyprint(IExpr)prettyprint(add(add(0, 5), 8)) “((0 + 5) + 8)”

I depth(IExpr)depth(add(add(0, 5), 8)) 3

I simplify()simplify(add(add(0, 5), 8)) add(5, 8)

I Bisher: Modellierung mit Composite Pattern

I Problem: Composite Pattern erfordert beim Hinzufugendie Modifikation aller Ausdruck-Klassen

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 12 / 25

Page 17: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Weitere Operationen fur Arithmethische AusdruckeModellierung mit Composite Pattern

Problem: Composite pattern erfordert Modifikation aller Ausdruck-Klassen

Implementierung der Operation ist uber viele Klassen verteilt

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 13 / 25

Page 18: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Operationen fur Arithmethische Ausdruckein einer idealen Welt

1 public static int eval(IExpr e) {2 /∗3 − falls e eine Const Instanz ist,4 dann return e.value5 − falls e eine Add Instanz ist,6 dann return eval(e.left) + eval(e.right)7 − falls e eine Produkt Instanz ist,8 dann return eval(e.left) * eval(e.right)9 ∗/

10 }

I Logik der Operation gesammelt an einer Stelle

I Ausdruck-Klassen bleiben unangetastet

I Es kann im Prinzip leicht gepruft werden ob alle Falle beachtetworden sind

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 14 / 25

Page 19: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Operationen fur Arithmethische Ausdruckein einer idealen Welt

1 public static int eval(IExpr e) {2 /∗3 − falls e eine Const Instanz ist,4 dann return e.value5 − falls e eine Add Instanz ist,6 dann return eval(e.left) + eval(e.right)7 − falls e eine Produkt Instanz ist,8 dann return eval(e.left) * eval(e.right)9 ∗/

10 }

I Logik der Operation gesammelt an einer Stelle

I Ausdruck-Klassen bleiben unangetastet

I Es kann im Prinzip leicht gepruft werden ob alle Falle beachtetworden sind

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 14 / 25

Page 20: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Keine wirkliche Losung: instanceof

1 public static int eval(IExpr e) {2 if (e instanceof Const) { // falls e eine Const Instanz ist3 Const c = (Const) e;4 return c.value;5 } else if (e instance of Add) { // falls e eine Add Instanz ist6 Add a = (Add) e;7 return eval(a.left) + eval(a.right)8 } else if (...) { // ...9 ...

10 } else { // Fehler, wenn kein Fall zutrifft11 return IllegalArgumentException...12 }13 }

I Repetitives, fehleranfalliges Muster:

if(e instanceof 〈Klasse〉) {〈Klasse〉 x = (〈Klasse〉) e; ...}

I Laufzeitfehler wenn ein Fall vergessen wird bei falschen Casts

. . . insbesondere wenn doch noch ein Fall nachtraglich hinzugefugt wird

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 15 / 25

Page 21: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Hinzufugen weiterer Operationen

Keine wirkliche Losung: instanceof

1 public static int eval(IExpr e) {2 if (e instanceof Const) { // falls e eine Const Instanz ist3 Const c = (Const) e;4 return c.value;5 } else if (e instance of Add) { // falls e eine Add Instanz ist6 Add a = (Add) e;7 return eval(a.left) + eval(a.right)8 } else if (...) { // ...9 ...

10 } else { // Fehler, wenn kein Fall zutrifft11 return IllegalArgumentException...12 }13 }

I Repetitives, fehleranfalliges Muster:

if(e instanceof 〈Klasse〉) {〈Klasse〉 x = (〈Klasse〉) e; ...}

I Laufzeitfehler wenn ein Fall vergessen wird bei falschen Casts

. . . insbesondere wenn doch noch ein Fall nachtraglich hinzugefugt wird

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 15 / 25

Page 22: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Visitors

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 16 / 25

Page 23: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Uberblick

I Die Operationen sind Implementierungen eines Visitor-Interfaces

I Ruckgabetyp einer Operation ist der generische Parameter T

I die verschiedenen Falle sind auf die visit∗ Methoden aufgeteilt

I Keine Typecasts und instanceof Test notig

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 17 / 25

Page 24: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Beispiel: Eval

1 class Eval implements IExprVisitor<Integer> {2 public Integer visitConst(Const c) {3 return c.value;4 }5 public Integer visitAdd(Add a) {6 return /∗ a.left + a.right ∗/;7 }8 public Integer visitProduct(Product p) {9 return /∗ p.left ∗ p.right ∗/;

10 }}

I . . .

I die verschiedenen Falle sind auf die visit∗ Methoden aufgeteilt

I Keine Typecasts und instanceof Test notig

Es bleibt zu klaren: Wie wird Eval aufgerufen?

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 18 / 25

Page 25: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Beispiel: Eval

1 class Eval implements IExprVisitor<Integer> {2 public Integer visitConst(Const c) {3 return c.value;4 }5 public Integer visitAdd(Add a) {6 return /∗ a.left + a.right ∗/;7 }8 public Integer visitProduct(Product p) {9 return /∗ p.left ∗ p.right ∗/;

10 }}

I . . .

I die verschiedenen Falle sind auf die visit∗ Methoden aufgeteilt

I Keine Typecasts und instanceof Test notig

Es bleibt zu klaren: Wie wird Eval aufgerufen?

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 18 / 25

Page 26: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Anwenden von Visitors

I Das Ausdruck-Interface (IExpr) muss das Visitor-Pattern unterstutzen:nur der Ausdruck selber weiß welcher Fall aufgerufen werden muss

I Dazu reicht eine Methode accept(IExprVisitor v)

I ,,Aufruf” der Operation: e.accept(new Eval())

Aufrufe im Vergleich

Composite Pattern

IExpr e = add(5, 4);Integer i = e.eval();String s = e.prettyPrint();

VisitorPattern

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 19 / 25

Page 27: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Anwenden von Visitors

I Das Ausdruck-Interface (IExpr) muss das Visitor-Pattern unterstutzen:nur der Ausdruck selber weiß welcher Fall aufgerufen werden muss

I Dazu reicht eine Methode accept(IExprVisitor v)

I ,,Aufruf” der Operation: e.accept(new Eval())

Aufrufe im Vergleich

Composite Pattern

IExpr e = add(5, 4);Integer i = e.eval();String s = e.prettyPrint();

VisitorPattern

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 19 / 25

Page 28: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Einschub: Generische MethodenDie Signatur von ,,accept’

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Die Methode accept muss zu IExpr hinzugefugt werden:

I <T> T accept(IExprVisitor<T> v) ist eine generische Methode.

I anders als bei generischen Klassen (vgl. List<T>),muss der Typparameter beim Aufruf meist nicht angegeben werden.

I ansonsten: String s = e.<String>accept(new PrettyPrint())

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 20 / 25

Page 29: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Einschub: Generische MethodenDie Signatur von ,,accept’

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Die Methode accept muss zu IExpr hinzugefugt werden:

interface IExpr {?? accept(IExprVisitor<??> v);

}

I <T> T accept(IExprVisitor<T> v) ist eine generische Methode.

I anders als bei generischen Klassen (vgl. List<T>),muss der Typparameter beim Aufruf meist nicht angegeben werden.

I ansonsten: String s = e.<String>accept(new PrettyPrint())

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 20 / 25

Page 30: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Einschub: Generische MethodenDie Signatur von ,,accept’

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Die Methode accept muss zu IExpr hinzugefugt werden:

interface IExpr {?? accept(IExprVisitor<??> v);// String accept(IExprVisitor<String> v)// Integer accept(IExprVisitor<Integer> v)}

I <T> T accept(IExprVisitor<T> v) ist eine generische Methode.

I anders als bei generischen Klassen (vgl. List<T>),muss der Typparameter beim Aufruf meist nicht angegeben werden.

I ansonsten: String s = e.<String>accept(new PrettyPrint())

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 20 / 25

Page 31: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Einschub: Generische MethodenDie Signatur von ,,accept’

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Die Methode accept muss zu IExpr hinzugefugt werden:

interface IExpr {<T> T accept(IExprVisitor<T> v);// String accept(IExprVisitor<String> v)// Integer accept(IExprVisitor<Integer> v)}

I <T> T accept(IExprVisitor<T> v) ist eine generische Methode.

I anders als bei generischen Klassen (vgl. List<T>),muss der Typparameter beim Aufruf meist nicht angegeben werden.

I ansonsten: String s = e.<String>accept(new PrettyPrint())

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 20 / 25

Page 32: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Einschub: Generische MethodenDie Signatur von ,,accept’

IExpr e = add(5, 4);Integer i = e.accept(new Eval());String s = e.accept(new PrettyPrint());

Die Methode accept muss zu IExpr hinzugefugt werden:

interface IExpr {<T> T accept(IExprVisitor<T> v);// String accept(IExprVisitor<String> v)// Integer accept(IExprVisitor<Integer> v)}

I <T> T accept(IExprVisitor<T> v) ist eine generische Methode.

I anders als bei generischen Klassen (vgl. List<T>),muss der Typparameter beim Aufruf meist nicht angegeben werden.

I ansonsten: String s = e.<String>accept(new PrettyPrint())

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 20 / 25

Page 33: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Anwenden von VisitorsI Das Ausdruck-Interface muss Visitor unterstutzen: nur der Ausdruck

selber weiß welcher Fall aufgerufen werden muss.I Dazu reicht eine Methode accept(IExprVisitor v)

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 21 / 25

Page 34: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Beispiel: Eval

1 class Eval implements IExprVisitor<Integer> {2 public Integer visitConst(Const c) {3 return c.value;4 }5 public Integer visitAdd(Add a) {6 return a.left.accept(this) + a.right.accept(this);7 }8 public Integer visitProduct(Product p) {9 return p.left.accept(this) ∗ p.right.accept(this);

10 }}

I . . .

I die verschiedenen Falle sind auf die visit∗ Methoden aufgeteilt

I Keine Typecasts und instanceof Test notig

I Implementierung von accept ist mechanisch.(d.h. die Methode konnte automatisch generiert werden)

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 22 / 25

Page 35: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Beispiel: Depth

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 23 / 25

Page 36: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Hinzufugen von Fallen

Ein arithmetischer Ausdruck ist entweder

I . . .

I oder eine Variable, z.B.: new Var(”x”)

Das Visitor-Pattern stellt sicher, dassalle Visitor-basierten Operationen nachgebessert werden mussen

I beim Hinzufugen von Fallen muss die accept Methode implementiertwerden (Teil von IExpr)

I dabei fallt auf, dass ein entsprechender visit∗ Fall fehlt

I der muss zum ∗Visitor Interface hinzugefugt werden

I was zwangsweise eine Anpassung aller konkreten Visitors nach sichzieht

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 24 / 25

Page 37: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Hinzufugen von Fallen

Ein arithmetischer Ausdruck ist entweder

I . . .

I oder eine Variable, z.B.: new Var(”x”)

Das Visitor-Pattern stellt sicher, dassalle Visitor-basierten Operationen nachgebessert werden mussen

I beim Hinzufugen von Fallen muss die accept Methode implementiertwerden (Teil von IExpr)

I dabei fallt auf, dass ein entsprechender visit∗ Fall fehlt

I der muss zum ∗Visitor Interface hinzugefugt werden

I was zwangsweise eine Anpassung aller konkreten Visitors nach sichzieht

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 24 / 25

Page 38: Programmieren in Java - uni-freiburg.de · Executive Summary | Visitor Pattern IDesign-Pattern, dass bei rekursiven Klassen Verwendung ndet I Es erlaubt einfaches und modulares Hinzufugen

Visitors

Eigenschaften des Visitor Patterns

Vorteile

I keine Casts oder instanceof checks

I Die Operationen mussen alle Falle behandeln.

NachteileFalle hinzufugen ist aufwendig(vgl. “Die Operationen mussen alle Falle behandeln”)

Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 25 / 25