Newsgroup: it.comp.java
Titolo: classi link bidirezionale

salve,
ho due classi: eventi e persone
eventi contiene la List degli iscritti,
e persone contiene la List degli eventi a cui è iscritto.
ovviamente quando una persona si iscrive ad un evento entrambe le liste
dovrebbero venire aggiornate contemporaneamente.
il mio problema è proprio garantire questo.
come fareste voi?
di seguito un po di codice di esempio
Grazie
Giulio
---------------
		persone pino = new persone();
		eventi festa = new eventi();
		pino.getAttivita().add(festa);
                //se mi dimentico la riga seguente il programma entra
in uno stato inconsistente
		festa.getPartecipanti().add(pino);
----------------
public class persone {
	List <eventi> attivita = new ArrayList<eventi>();
---------------
public class eventi {
List <persone> partecipanti = new ArrayList<persone>();

// ho due classi: eventi e persone
// eventi contiene la List degli iscritti,
// e persone contiene la List degli eventi a cui č iscritto.
//
// ovviamente quando una persona si iscrive ad un evento entrambe le liste
// dovrebbero venire aggiornate contemporaneamente.
//
// il mio problema č proprio garantire questo.
//
// come fareste voi?
Puoi fare un gestore che si occupa dell'inserimento di una nuova
persona sotto un nuovo evento: un unico metodo effettua entrambe
le chiamate in modo che la coerenza sia garantita.
Le chiamate:
  pino.getAttivita().add(festa);
  festa.getPartecipanti().add(pino);
non mi piacciono per niente.
Il resto mi piace molto poco.
Cosa hai bisogno di gestire, un po' piů in generale?
(Naturalmente tutto senza DB, vero?)
-- 
lpb
"I'm a poor lonesome cowboy, and a long, long way from home..."

 (Naturalmente tutto senza DB, vero?)
in realtà il db c'è, interamente gestito via hibernate. 
grazie
G

// cos'hanno di brutto? come faresti tu?
Immagino che tu abbia sintetizzato ma i concetti rimangono sempre gli stessi
ed il codice che hai scritto sembra poco ad oggetti...
// // Cosa hai bisogno di gestire, un po' più in generale?
// devo gestire degli oggetti che appartengono ad alcune categorie, con un
// rapporto many to many
// (ogni oggetto molte categorie ogni categoria molti oggetti)
Ok, ma è un po' pochino: chi deve avere riferimento a quegli oggetti,
ed in che modo? Così in generale ti direi che è preferibile una terza
classe che faccia da mappatura tra le due, come in un db relazionale;
ma dipende da come poi devi usarle...


 ma dipende da come poi devi usarle...
non capisco bene come lo faresti.
una specie di facade/indirection?
da qualche parte però dovrò sicuramente avere un metodo
public List(Evento) getEventi(){ return eventi; }
che potrà essere usato con getEventi().add(evento).
e quindi anche con il controller sono sempre punto e a capo.

Risposta cumulativa:
// festa.getPartecipanti().add(pino);
Male: accesso diretto all'elenco dei partecipanti, sarebbe meglio:
festa.addPartecipante(pino);
Quello che ti dicevo è una classe Calendario (tanto per dale un nome):
Calendario cal
cal.addEvento(festa)
cal.addPartecipante(pino)
cal.associa(festa, pino)
cal.getEventi()
cal.getEventi(pino)
cal.getPartecipanti()
cal.getPartecipanti(festa)
o qualcosa del genere; che dici?


Giulio ha scritto:

Secondo me è meglio pensare il problema in termini di db (anche se nno
necessariamenti li devi usare). Per una cosa di questo tipo avresti
bisongo di 3 tabelle, di cui una lega le due precedenti. Quindi fai una
terza classe con almeno 3 metodi
1 - addEventoPersona( persona , Evento )
2 - getListPersone ( evento )
3 - getListEventi( persona )

 come fareste voi?
E' un problema tipico che si risolve implementando l'observer pattern.
http://en.wikipedia.org/wiki/Observer_pattern
http://www.javaworld.com/javaworld/javaqa/2001-05/04-qa-0525-observer.html

 
http://www.javaworld.com/javaworld/javaqa/2001-05/04-qa-0525-observer.html
mh... mi sembra un po complesso con l'observer...
e poi come dovrei fare in una situazione più complessa in cui per
esempio in ogni evento ho anche una lista di organizzatori:
List<Persona> organizzatori;
linkato con una lista di eventi organizzati in Persona:
List<Evento> eventiOrganizzati
dovrei notificare separatamente i due eventi?
dovrei riuscire a distinguere in qualche modo i due differenti eventi
nei metodi update?

 nei metodi update?
Dovrei entrare nel dettaglio del codice, ma se tu definisci una classe 
Evento che wrappa tutte le informazioni relative al cambio di stato e lo 
passi al metodo di notifica, sta poi all'implementazione del metodo 
decidere cosa fare.
Posso suggerirti di vedere cosa fanno le swing, un esempio classico è 
l'interfaccia MenuListener.
http://java.sun.com/j2se/1.5.0/docs/api/javax/swing/event/MenuListener.html
Le swing notificano l'implementazione di quale evento si è verificato e 
da quale oggetto è stato generato, poi chiaramente sta 
all'implementazione agire di conseguenza.

 è meglio scriverlo. Purtroppo in Java non esistono gli eventi come nel C#.
Il fatto è che la classe List non è Observable, quindi non mi
notifica i cambiamenti alla lista.
io posso solamente dichiarare le classi 'eventi' e 'persone' come
observable e sparare la notifica da dentro i miei metodi 'add' e
'remove'.
questo però mi lascia comunque esposto all'uso improprio dei metodi
List<eventi> getiscrizioni() e List<persone> getIscritti().
che possono essere usati come nel primo esempio
(getEventi().add(evento)) e questo resterebbe non notificato e quindi
fantasma.
La soluzione sarebbe dal getEventi restituire una copia della lista, in
modo che la List contenuta in persone non possa essere modificata.
ma a quanto pare la classe List non implementa neppure Cloneable,
quindi è il solito macello.
di seguito il codice completo di quello che ho fatto con gli observer.
attenzione che va in stack overflow, xchè le notify effettuano
modifiche che chiamano altre notify all'infinito.
------------------------------------------------
import java.util.*;
public class prova implements Observer {
	public static void main(String[] args) {
		new prova();
	}
	persone pino = new persone();
	eventi festa = new eventi();
	eventi concerto = new eventi();
	persone franco = new persone();
	public prova(){
		festa.addObserver(this);
		concerto.addObserver(this);
		pino.addObserver(this);
		franco.addObserver(this);
		festa.addPartecipante(pino);
		pino.addAttivita(concerto);
		festa.addPartecipante(franco);
	}
	public void update(Observable o, Object arg) {
		if (o.getClass().equals(persone.class)) {
			//una persona ha notificato xchè è stata iscritta ad un'evento
			System.out.println("persone updated :"+ arg);
			persone personaIscritta  = (persone)o;
			eventi eventoAggiornato = (eventi)arg;
			eventoAggiornato.addPartecipante(personaIscritta);
		}else if (o.getClass().equals(eventi.class)) {
//			un evento ha notificato xchè è stata iscritta una persona
			System.out.println("eventi updated :"+ arg);
			persone personaIscritta  = (persone)arg;
			eventi eventoAggiornato = (eventi)o;
			personaIscritta.addAttivita(eventoAggiornato);
		}else {
			System.out.println("ERRORE: update not identified :"+ o);
		}
	}
}
class eventi extends Observable{
	private List<persone> partecipanti = new ArrayList<persone>();
	public List<persone> getPartecipanti() {
		return partecipanti;
	}
	public void addPartecipante(persone persona) {
		setChanged();
		this.partecipanti.add(persona);
		notifyObservers(persona);
	}
}
class persone extends Observable{
	private List<eventi> attivita = new ArrayList<eventi>();
	public List<eventi> getAttivita() {
		return attivita;
	}
	public void addAttivita(eventi attivita){
		this.attivita.add(attivita);
		setChanged();
		notifyObservers(attivita);
	}
}

prima che mi cazziate..
ho fatto quel codice da overflow anche per mostrare come in ogni caso,
con questo approccio sia necessaria la presenza di un metodo per
aggiornare il contenuto di una delle liste senza notificare.
ma la cosa potrebbe essere implicita, per esempio evitando di
aggiungere doppioni alla lista. (però in questo caso non potrei più
mettere doppioni nella lista)

 quindi è il solito macello.
Ti perdi in un bicchiere d'acqua :-)
ArrayList o Vector hanno entrambi un costruttore di copia.

 ArrayList o Vector hanno entrambi un costruttore di copia.
argh... è vero... quindi quella parte è risolta, allora risolvo
usando il modo più semplice e veloce
faccio i componenti delle entità package-protected in modo che siano
modificabili da oggetti dello stesso package, e nei metodi getter di
questi componenti restituisco copie, in modo che i componenti siano
modificabili solamente tramite i metodi add e remove.
grazie mille per l'aiuto. 
G