Esplora E-book
Categorie
Esplora Audiolibri
Categorie
Esplora Riviste
Categorie
Esplora Documenti
Categorie
Visitor Base
Pertanto, parlando in termini del pattern Visitor:
In base alla competenza:
1. la prima struttura definisce gli Element che detengono lo stato
2. la seconda struttura definisce i Visitor che detengono i comportamenti
In base allordine di invocazione:
1. Il Client invoca il metodo accept() presente nellElement passandogli in ingresso un oggetto Visitor
2. LElement invoca il metodo visit() del Visitor passandogli se stesso (oggetto this) come parametro.
3. Il Visitor, disponendo della referenza allElement (tramite loggetto this) accede alle propriet
dellElement ed eseguire le operazioni.
Vediamo la rappresentanzione UML usando il Sequence Diagram:
consentire questo scambio di messaggi tra lElement ed il Visitor, pertanto risulta un po complesso
considerando che utilizza polimorfismo, overriding ed overloading.
Partecipanti e Struttura
Questo pattern composto dai seguenti partecipanti:
Element: definisce il metodo accept() che prende un Visitor come argomento
ConcreteElement: implementa un oggetto Element che prende un Visitor come argomento
ObjectStructure: contiene una collezione di Element che pu essere visitata dagli oggetti Visitor
Visitor: dichiara un metodo visit() per ogni Element; il nome del metodo ed il parametro
identificano la classe Element che ha effettuato linvocazione.
ConcreteVisitor: implementa il metodo visit() e definisce lalgoritmo da applicare per lElement
passato come parametro
Vediamo come si presenta il Pattern Visitor utilizzando il Class Diagram in UML:
necessit che tra di essi ci sia un vincolo di parentela. In poche parole, il metodo visit() pu definire
come parametro un tipo X oppure un tipo Y senza che tra di essi ci sia alcuna relazione di parentela,
diretta o indiretta.
Accumulazione dello stato: un Visitor pu accumulare delle informazioni di stato a seguito
dellattraversamento degli Element.
Violazione dellincapsulamento: i Visitor devono poter accedere allo stato degli Element e questo
pu comportare la violazione dellincapsulamento.
Implementazione
Il pattern Visitor suscita sensazioni di odio-amore (qui o qua) e ci molto comprensibile a causa della
sua complessit e dei suoi limiti. Inoltre non semplice identificare la casistica in cui utilizzarlo anche a
fronte del fatto che, se le specifiche cambiano, questo pattern resta molto faraginoso da mantenere.
Partendo da questa premessa si capisce che non sar semplice spiegarlo pertanto utilizzer un approccio
incrementale, partendo da un esempio semplice per poi complicarlo. Nella sua forma pi semplice questo
pattern esprime semplicemente il Double Dispatch che ne costituisce la sua natura che occorrer rivedere.
Inoltre occorre osservare che questo pattern stato oggetto di proposte di rivisitazione, ma in questo
contesto mi limiter ad usarlo nella sua forma originaria.
Come esempio, ho pensato a queste implementazioni:
1.
2.
3.
4.
5.
1. Hello Visitor
Per iniziare riprendo lesempio fatto allinizio, il pi semplice possibile, al fine di invocare un
comportamento, definito in una classe Visitor, su di uno stato, definito in una classe Element. Un semplice
Hello Visitor!.
Definiamo la classe Element che definisce lo stato (propriet hello), laccessor (metodo getHello()) ed il
collegamento con il Visitor(metodo accept()):
1
2
3
4
5
6
7
8
9
10
11
12
13
package patterns.visitor.hello;
public class Element {
private String hello = "Element";
Definiamo la classe Visitor che definisce la modalit di interfacciamento con lElement (metodo visit())
che, accettando come paramentro loggetto Element, sar in grado di recuperare lo stato dellElement
tramite il suo accessor (metodo getHello())
1
2
3
4
package patterns.visitor.hello;
public class Visitor {
5
6
7
8
9
Per simulare la loro interazione definiamo la classe Client che si occupa di invocare lElement passando al
metodo accept() il Visitor che definisce il comportamento da adottare.
1
2
3
4
5
6
7
8
9
10
package patterns.visitor.hello;
public class Client {
public static void main(String[] args) {
Element element = new Element();
element.accept( new Visitor() );
}
}
$JAVA_HOME/bin/java patterns.visitor.hello.Client
Hello Element
Aria Rettangolo
Vediamo come si presenta il Sequence Diagram in UML in base allesempio:
Definiamo la classe ElementRettangolo che detiene le informazioni dello stato del rettangolo ( ossia
altezza e larghezza), i metodi accessor e mutator (ossia i get() e set() ) ed il metodo di accesso e di dialogo
con il Visitor (metodo accept())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package patterns.visitor.rettangolo.aria;
public class ElementRettangolo {
private int altezza;
private int larghezza;
public int getAltezza() {
return this.altezza;
}
public void setAltezza(int altezza) {
this.altezza = altezza;
}
public int getLarghezza() {
return this.larghezza;
}
public void setLarghezza(int larghezza) {
this.larghezza = larghezza;
}
1
2
3
4
5
6
7
8
package patterns.visitor.rettangolo.aria;
Definiamo la classe Client che setta le propriet del rettangolo, ossia il suo stato, e poi si avvale del
Visitor, VisitorRettangoloAria, per calcolare la sua area.
1
2
3
4
5
6
7
8
9
10
package patterns.visitor.rettangolo.aria;
$JAVA_HOME/bin/java patterns.visitor.rettangolo.aria.Client
L'area del rettangolo e': 200
Dobbiamo definire una classe padre dei Visitor, che prima non avevamo, al fine di definire tutte le
operazioni presenti.
In particolare abbiamo le operazioni relative al calcolo dellaria e del perimetro del rettangolo.
1
2
3
4
5
6
7
8
9
package patterns.visitor.rettangolo.ariaPerimetro;
abstract class Visitor {
Di seguito dobbiamo relazionare la classe VisitorRettangoloAria con il padre e definire entrambi i metodi.
Ovviamente il metodo relativo al calcolo del perimetro non dovr essere implementato.
1
2
3
4
5
6
7
8
9
package patterns.visitor.rettangolo.ariaPerimetro;
public class VisitorRettangoloAria extends Visitor {
@Override
public void visitRettangoloAria(ElementRettangolo elementRetta
int aria = elementRettangolo.getAltezza() * elementRettang
System.out.println("L'area del rettangolo e': "+ aria);
}
10
11
12
13
14
15
16
@Override
public void visitRettangoloPerimetro(ElementRettangolo element
throw new UnsupportedOperationException("Not supported.");
}
}
Adesso definiamo laltro Visitor, VisitorRettangoloPerimetro, che si occupa di calcolare il perimentro del
rettangolo. Come nel caso precedente, dobbiamo prevedere entrambi i metodi ma dobbiamo implementare
solo quello di interesse: visitRettangoloPerimetro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package patterns.visitor.rettangolo.ariaPerimetro;
public class VisitorRettangoloPerimetro extends Visitor {
@Override
public void visitRettangoloAria(ElementRettangolo elementRetta
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void visitRettangoloPerimetro(ElementRettangolo element
int perimentro = (elementoRettangolo.getAltezza() + element
System.out.println("Il perimetro del rettangolo e': " + per
}
}
package patterns.visitor.rettangolo.ariaPerimetro;
public class ElementRettangolo {
private int altezza;
private int larghezza;
public int getAltezza() {
return this.altezza;
}
public void setAltezza(int altezza) {
this.altezza = altezza;
}
public int getLarghezza() {
return this.larghezza;
}
public void setLarghezza(int larghezza) {
this.larghezza = larghezza;
}
23
24
25
26
27
28
29
30
31
Infine nella classe Client possiamo invocare il nostro Client che si occupa di creare il rettangolo e
successivamente di invocare le operazioni relative al calcolo dellaria e del perimetro in base al tipo di
Visitor che viene passato.
1
2
3
4
5
6
7
8
9
10
11
12
13
package patterns.visitor.rettangolo.ariaPerimetro;
public class Client {
$JAVA_HOME/bin/java patterns.visitor.rettangolo.ariaPerimetro.Clien
Il perimetro del rettangolo e': 60
L'area del rettangolo e': 200
Triangolo e Rettangolo
Vediamo come si presenta il Sequence Diagram in UML in base allesempio:
package patterns.visitor.triangolo;
public class ElementTriangoloRettangolo extends Element{
private int base;
private int altezza;
public int getBase() {
return base;
}
public void setBase(int base) {
this.base = base;
}
public int getAltezza() {
return altezza;
}
public void setAltezza(int altezza) {
this.altezza = altezza;
}
@Override
public void accept(Visitor visitor) {
26
27
28
29
30
31
32
Vediamo come si presenta linterfaccia Visitor a seguito dellinserimento dei metodi invocati dal nuovo
Element:
1
2
3
4
5
6
7
8
9
10
11
12
package patterns.visitor.triangolo;
public abstract class Visitor {
package patterns.visitor.triangolo;
public class VisitorTriangoloRettangoloAria extends Visitor {
@Override
public void visitRettangoloAria(ElementRettangolo elementRetta
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void visitRettangoloPerimetro(ElementRettangolo element
throw new UnsupportedOperationException("Not supported.");
}
@Override
public void visitTriangoloRettangoloAria(ElementTriangoloRetta
int aria = ((elementTriangoloRettangolo.getBase() * elemen
System.out.println("L'area del triangolo e': " + aria);
}
@Override
public void visitTriangoloRettangoloPerimetro(ElementTriangolo
throw new UnsupportedOperationException("Not supported.");
}
}
ed il secondo Visitor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package patterns.visitor.triangolo;
@Override
public void visitRettangoloAria(ElementRettangolo elementRetta
throw new UnsupportedOperationException("Not supported yet
}
@Override
public void visitRettangoloPerimetro(ElementRettangolo element
throw new UnsupportedOperationException("Not supported yet
}
@Override
public void visitTriangoloRettangoloAria(ElementTriangoloRetta
throw new UnsupportedOperationException("Not supported yet
}
@Override
public void visitTriangoloRettangoloPerimetro(ElementTriangolo
int perimetro = (elementTriangoloRettangolo.getBase() + (e
System.out.println("Il perimetro del triangolo e': " + per
}
}
package patterns.visitor.triangolo;
public class Client {
ElementTriangoloRettangolo elementTriangoloRettangolo = ne
elementTriangoloRettangolo.setBase(10);
elementTriangoloRettangolo.setAltezza(20);
elementTriangoloRettangolo.accept( new VisitorTriangoloRet
elementTriangoloRettangolo.accept( new VisitorTriangoloRet
$JAVA_HOME/bin/java patterns.visitor.triangolo.Client
Il perimetro del rettangolo e': 60
L'area del rettangolo e': 200
Il perimetro del triangolo e': 50
In questo caso la modifica consiste nellintroduzione della classe Struttura che avr il compito di
inizializzare ed invocare gli elementi contenuti nella propria lista. Vediamo meglio:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package patterns.visitor.triangolo;
import java.util.Iterator;
import java.util.Vector;
public class Struttura extends Vector {
public Struttura(){
ElementRettangolo elementRettangolo = new ElementRettangol
elementRettangolo.setAltezza(10);
elementRettangolo.setLarghezza(20);
add( elementRettangolo);
ElementTriangoloRettangolo elementTriangoloRettangolo = ne
elementTriangoloRettangolo.setBase(10);
elementTriangoloRettangolo.setAltezza(20);
add( elementTriangoloRettangolo );
27
28
29
30
element.accept(new VisitorTriangoloRettangoloPerimetro
In questo caso il Client si presenta pi snello in quanto deve semplicemente invocare la classe Struttura,
che per noi funge da Facade:
1
2
3
4
5
6
7
8
9
10
package patterns.visitor.triangolo;
public class Client {
public static void main(String[] args) {
Struttura struttura = new Struttura();
struttura.esegui();
}
}
$JAVA_HOME/bin/java patterns.visitor.triangolo.Client
L'area del rettangolo e': 200
Il perimetro del rettangolo e': 60
L'area del triangolo e': 100
Il perimetro del triangolo e': 50
1.
77
SCEGLI
Firenze - Alghero
Solo andata
126
SCEGLI
Milano - Alghero
Solo andata
83
SCEGLI
Share this:
Stampa
Mi piace
Di' per primo che ti piace.
Articoli collegati
1.
Alessandro
15 luglio 2013 alle 12:12 AM
Rispondi
Ciao! Grazie per la spiegazione esauriente!
davvero utile. Sapresti indicarmi qualche fonte per
informazioni pi approfondite sullargomento?
Ps. Nellesempio 1. Hello Visitor perch il metodo getHello() definito come mutator e non come
accessor?
Giuseppe Dell'Abate
15 luglio 2013 alle 11:01 AM
Rispondi
Puoi trovare approfondimenti in questi link, ma ce ne sono decisamente tanti altri.
The Essence of the Visitor Pattern
The Visitor Pattern
The VISITOR Pattern as a Reusable, Generic, Type-Safe Component
Visitor Pattern
Visitor Design Pattern
COSC3311 Software Design Visitor Pattern
The Visitor Pattern
Visitor pattern
PS: Decisamente una svista che correggo subito! Grazie mille. Ciao.
2.
Dennis
12 gennaio 2014 alle 12:02 PM
Rispondi
Ciao, grazie per la bellissima spiegazione di questo pattern.
Ma, come hai fatto ad esempio nellesercizio 3, una classe abstract che contiene tutti i metodi
abstract non sarebbe meglio dichiararla come interface?
Giuseppe Dell'Abate
31 gennaio 2014 alle 1:21 PM
Rispondi
Ciao, grazie per i complimenti e scusa per il ritardo con cui ti scrivo.
Sicuramente si, in questo caso una interfaccia va benissimo.
Solitamente preferisco utilizzare le classi astratti in quanto si prestano meglio in caso di
refactoring, per esempio posso dichiarare dei metodi concreti disponibili a fattor comune per
le classi figlie ed applicare facilmente il template pattern.
Inoltre secondo un mito, forse esagerato, le classi astratte sono pi veloci delle interfacce:
http://stackoverflow.com/questions/12514131/which-one-is-fast-abstract-class-or-interface.
Puoi vedere altre differenze tra le due qui:
http://mindprod.com/jgloss/interfacevsabstract.html
1. No trackbacks yet.
Rispondi
Concorrenza in Java: Thread, Executor e Fork/Join Simple, Double e Multi Dispatch in Java
RSS feed
Articoli recenti
Internet ed il web
Algoritmi e struttura dati
J2EE Patterns: Intercepting Filter
Bad Practices: Presentation, Business e Integration Tiers
Architettura Esagonale
Tell, dont Ask
Concorrenza in Java: Thread, Executor e Fork/Join
GoF Patterns: Visitor
Simple, Double e Multi Dispatch in Java
GoF Patterns: Template Method
GoF Patterns: Strategy
GoF Patterns: State
GoF Patterns: Observer
GoF Patterns: Memento
GoF Patterns: Mediator
Archivio mensile
febbraio 2014 (1)
novembre 2013 (2)
ottobre 2013 (3)
giugno 2013 (1)
aprile 2013 (1)
novembre 2012 (1)
agosto 2012 (1)
luglio 2012 (1)
marzo 2012 (2)
Post pi letti
La tecnica della ricorsione in Java
Utilizzo dei Socket su protocolli UDP/IP
GoF Patterns: Decorator
GoF Patterns: Observer
GoF Patterns: Chain of Responsibility
GoF Patterns: Strategy
GoF Patterns: State
Utilizzo dei Socket su protocolli TCP/IP
Concorrenza in Java: Thread, Executor e Fork/Join
Libri
Calendario
aprile: 2013
L MMG V S D
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
nov
giu
Blogroll
ClsHack
infoQ
javalobby
javaranch
javaworld
Statistiche
My del.icio.us
JSF 2.0 Tutorial
PrimeFaces - ShowCase
JVM Troubleshooting Tools
PrimeFaces Tutorial (Prime Faces for JSF 2) with Eclipse
Eclipse IDE for Java EE Developers | Packages
Liferay Logical Architecture
MokaByte 176 - Settembre 2012 - Java e i portali
Find Security Bugs
Automated Security Testing of web applications using OWASP Zed Attack Proxy - codecentric
Blog
Plugins - Jenkins
SecurityDistros
Unicornscan - BackTrack Linux
Kali Linux Tools Listing
How to resize a VirtualBox vmdk file - Stack Overflow
Fritzing
Bionic Arduino Introduction to Microcontrollers with Arduino todbot blog
Apache Tomcat 6.0 (6.0.41) - Clustering/Session Replication HOW-TO
Tomcat 6 - Clustering
Introduction to Selenium Grid
Expert Cheat Sheets & Tutorial Guides for Developers | Refcardz
Enterprise Integration Patterns - Integration Patterns Overview
Home - Dr. Garbage
OWASP LAPSE Project - OWASP
Eclipse Control Flow Graph Generator
The Trac Project
Mantis Bug Tracker
The wise work manager for context-based scoping | JavaWorld
Java EE: Schedule jobs with WorkManager
Kumar's Blog: The Work Manager API: Parallel Processing Within a J2EE Container
Guida per risolvere il cubo di Rubik
Grafi: concetti fondamentali e problemi notevoli - Ricerca operativa
Change UUID of Virtual Drive (VDI) in VirtualBox
Coursera
Scratch - Imagine, Program, Share
Java Pattern Wizard - Java Developer Tools Google Developers
Technical debt
Lehman's laws of software evolution
Enterprise Integration Patterns - Table of Contents
Apps e Widget per Android
Problema con la memoria Android? Ecco come risolverlo!
Certification and Training for Software Professionals| IEEE Computer Society
Oracle Partitioning Concepts
Top 10 Java Business Rule Engines
Jess, the Rule Engine for the Java Platform - Introduction to Programming with Jess in Java
JDBC RowSet Example
Structure and Interpretation of Computer Programs
High Scalability - All Time Favorites
Redmine