Newsgroup: it.comp.lang.c++
Titolo: Collezioni di oggetti con diverse informazioni: come trattarle?

Ho un problema per il quale al momento ho trovato due soluzioni 
alternative senza essere completamente soddisfatto da nessuna delle due.
Mi è capitato più volte di dover gestire collezioni di oggetti 
eterogenei ad esempio una lista di eventi dove tutti gli oggetti sono, 
appunto, eventi ma ognuno possiede informazioni di tipo diverso. Un 
evento "MouseClick" conterrà informazioni sul punto dove il click è 
avvenuto e il bottone del mouse premuto, un evento "KeyPress" conterrà 
informazioni sul tasto premuto e così via.
1° Soluzione
Creo una classe base Event e delle classi derivate
class Event
	virtual	void getType( std::string& typeName ) const = 0;
class MouseClick
	virtual	void getType( std::string& typeName ) const
	void getPoint( Point& clickPoint ) const;
	void getButton( Button& button ) const;
Ogni volta che tratto un Event uso il metodo getType e a seconda del 
risultato faccio un cast esplicito a una classe derivata (ottengo 
"MouseClick" da getType? Faccio un cast a MouseClick *).
2° Soluzione
La classe Event ha dei metodi per associare a dei "nomi" dei valori
così posso associare a "MousePosition" il valore "7,3"
 
class Event
	virtual	void getType( std::string& typeName ) const = 0;
	void setAttribute( const std::string& name,
		const std::string& value );
	bool getAttribute( const std::string& name ) const;
Quando tratto un oggetto Event uso getType e a seconda del risultato 
chiedo all'oggetto diversi attributi. Per un evento di tipo "KeyPress" 
chiederò l'attributo "Key" ad esempio.
Cosa ne pensate di queste soluzioni? Avete alternative migliori da 
suggerirmi?
Grazie a tutti,
Federico

Personalmente non vedo alternative migliori alle due che presenti. Nel
caso del tuo esempio prependerei per la prima perche' se anche il cast
e' un'operazione relativamente costosa e' piu' che compensato dal non
dover continuare a confrontare stringhe.
Ciao,
Nicola

 
Suggerirei il pattern Visitor.
Max


Devo ammettere che non vedo come Visitor potrebbe aiutarmi anche perchč 
devo ammettere di non conoscerlo molto bene. Il mio problema non č 
gestire le stesse operazioni in maniera diversa a seconda della classe 
concreta. Qualcuno potrebbe farmi un esempio di come potrei utilizzarlo 
nella questione degli Eventi di cui parlvo nel primo post?
Grazie, Federico

 appunto, eventi ma ognuno possiede informazioni di tipo diverso. 
OK, qui andiamo verso un problema specifico.
Secondo me, se vuoi gestire eventi, la cosa migliore e' agganciare ad 
ogni oggetto che scatena l'evento un listener.
es. Hai un bottone, che scatena l'evento MouseClick.
Allora tale bottone avra' un metodo che consente di agganciarli una 
classe che, non appena si verifica l'evento, viene invocata (o meglio: 
si invoca un suo metodo).
Avrai la classe base Event, e da questa derivi MouseClick, etc.
Poi avrai la classe base EventListener, e da questa derivi i vari listener.
In una classe diciamo Button, avrai un metodo tipo addListener() al 
quale agganci un EventListener. Quando il bottone e' premuto, e' lui 
stesso che chiama l'apposito metodo di EventListener.
In altri termini, eviterei il piu' possibile gli switch sui tipi, come 
invece mi pare di capire tu voglia fare.
E' chiaro che nella classe Event potresti anche mettere una std::string 
getEventType(), pero' secondo me se fai poi degli switch sul tipo di 
evento, perdi molto del polimorfismo...
Ciao,
Dan


La tua soluzione è interessante ma va bene solo con gli eventi (io 
cercavo qualcosa di generale, quello degli eventi era un esempio) e non 
mi permette di gestire gli eventi come una coda o di conservarli ma mi 
impone di reagire immediatamente, io cercavo qualcosa di un pò diverso
Federico

 
Mi sembrava che la tua necessità fosse, data una lista di oggetti accomunati
da una certa interfaccia base (Event), riuscire a trattare ciascuno
utilizzando un'interfaccia più specializzata (ad es. MouseClick).
Considera l'esempio illustrato in questa pagina:
 
http://www.swe.uni-linz.ac.at/research/deco/designPatterns/Visitor/visitor.defaultroles.c++.html
Il problema che affronta mi pare assomigli al tuo. L'uso del double-dispatch
permette di spostare al gestione dei singoli oggetti (Element) in un punto
(cioè una funzione del Visitor) in cui l'oggetto sarà accessibile mediante
un'interfaccia più specializzata (ElementA o ElementB).
Max