Newsgroup: it.comp.java
Titolo: problema con comunicazione fra classi

Non è facile esporre il mio problema, cercherò di essere chiaro, ma...
Il mio programma di occupa di una specie di robot che si muove in un mondo
pieno di ostacoli e deve cercare di raggiungere un goal evitandoli.
La classe principale è "Applet", la classe da cui viene creato tutto. Questa
classe si occupa principalmente del disegno ma poi fa anche partire il
"cuore" del programma, creando varie classi, fra cui la classe "Mondo" e
"Robot".
La classe Applet ha un "Menu", il quale a sua volta crea la classe
"Prefererenze". (composta da vari pannelli "OpzioniQualcosa" per scegliere
le opzioni).
Con il pannello Preferenze l'utente può scegliere varie opzioni, che
modificano il comportamento del Robot e del Mondo.
Finora queste opzioni io le memorizzavo in dei campi <public static boolean
o int> di una classe generale "Constants".
Mentre il Mondo evolveva controllava questi flag e tutto andava bene...
Ora però ho creato un'altra classe "Voronoi" che ha bisogno per funzionare
di prendere in input i campi delle classi Mondo e Robot. (in particolare le
loro posizioni, aree, ecc...)
Dato che la creazione di questa classe è pesante (e opzionale) ho pensato
bene di aggiungere un'altro pannello alla classe Preferenze, dove con un
bottone l'utente può creare la classe Voronoi e attendere allegramente che
venga creata.
E qui sta il punto tragico!  La classe Applet è l'unica che abbia accesso
diretto ai campi di Robot e Mondo (dato che li crea lei) ed è del tutto
scollegata alle classi Menu e Preferenze!
Come cavolo faccio a fare in modo che quando l'utente clicca sul pulsante la
classe Applet esegua lei stessa un metodo per creare Voronoi?
(Cioè Applet e OpzioniVoronoi dovrebbero in qualche modo comunicare fra
loro, anche se nessuna delle due possiede istanze dell'altra. )
Ho pensato a due soluzioni, entrambe pessime.
1) La prima sarebbe appunto continuare con campi <static> di Constants. La
classe OpzioniVoronoi, dopo che l'utente ha cliccato, pone a true un flag.
La classe Applet all'interno di run controlla il flag e se è true, crea
Voronoi, e poi rimette il flag a false. A parte la "bruttezza" di ciò (per
ogni nuova cosa, nuovo campo static!) ci sarebbe anche un'altro problema.
Nel pannello delle opzioni vorrei visualizzare questa classe Voronoi, e
poterci interagire (altro campo static questa volta che si riferisce a una
classe?).
2) La seconda sarebbe passare la classe Applet al costruttore di Menu e da
questo al costruttore di Preferences e da questo al costruttore di
OpzioniVoronoi... Così ce l'avrei già li (ehm). Questo mi sembra addirittura
peggiore!
Dopo questa estenuante spiegazione spero che qualcuno ci abbia capito
qualcosa e mi sappia dare un consiglio!


Ciao!
Ho letto più volte ma credo di non aver capito bene, sorry.
Evitando il funzionamento pratico, ho capito che
1) hai *definito* le seguenti classi a livello di codice:
Applet
Mondo
Robot
Menu
Preferenze
Constants
Voronoi.
2) Il main è Applet, giusto?
3) Questa classe cosa *istanzia* che cosa? Da quello che capisco istanzia:
Mondo
Robot
Menu
Preferenze
Constants (qui ho qualche dubbio)
4) chi istanzia Voronoi?
5) immaginerei quacosa del tipo che in Applet ti ritrovi con
Preferenze pref = new Preferenze();
Constants costanti = new Constants();
...
Voronoi vn = new Voronoi();
6) A questo punto vn deve leggere valori di pref e/o costanti?
Scusa il terzo grado ma vorrei capire come è organizzata la struttura.
Alex.
-- 
___________________________________________________________
a p bertolini
(
www.webwarrior.org
)

 Non Š facile esporre il mio problema, cercher• di essere chiaro, ma...
..non e' che ti sia riuscito troppo :-) , ma da quanto mi par di capire 
che c'e' un pattern che ti puo' esser d'aiuto - che e' una specie di 2) 
riveduto e corretto.
Lo scopo e' di condividere oggetti X contenuti da un oggetto A con uno o 
piu' oggetti B, senza pero' accoppiare A e B, e in modo che A mantenga 
chiaramente la proprieta' di X.
Supponi A contenga un riferimento x ad un oggetto di classe X. Il trucco 
e' semplicemente di definire un'interfaccia XProvider, che viene 
implementata da A, che contiene i metodi necessari per accedere ad X.
B definisce un costruttore che accetta un XProvider, lo mantiene nel suo 
stato, e lo usa ogni volta che deve accedere all'istanza di X.
Esempio:
interface XProvider { 
 public X getX();
}
class A implements XProvider {
  private X x;
  public X getX() { return x; }
}
class B {
  private XProvider xProvider;
  public B(XProvider xProvider) { this.xProvider=xProvider;}
  public void faiQualcosaConX() {
    xProvider.getX().metodoDiX();
  }
}
-- 
You dont know what to do when you dont know what you're doing.
http://space.tin.it/computer/csadun

 }
class OpzioniVoronoi {
  private VoronoiProvider vProvider;
  public OpzioniVoronoi(VoronoiProvider vP) {
        vProvider = vP;   // qui gli passo come argomento l'istanza della
classe Applet !!!
}
  // click sul pulsante ...
  public void costruisciMappa() {
    Voronoi v = new Voronoi(vProvider.getRobotArea(),
vProvider.getOstacoliArea()) {
      // mentre costruisco l'oggetto Voronoi aggiorno il progress bar
      // quando ha finito lo posso passare alla classe Applet (aggiungo un
metodo all'interfaccia)
    }
}
quindi in effetti sarebbe come il punto 2) che avevo pensato, solo che
invece di passargli direttamente la classe gli passo sempre la classe ma
"mascherata" dall'interfaccia???

 Giusto? o mi sfugge qualcosa....
Giusto. Uno degli scopi del pattern e' (anche) quello di disaccoppiare il 
possesso (nel senso di membership) di un oggetto dal suo uso.
Creando le catene di cui sopra, ogni classe a cui serve una risorsa, ne 
ricevera' il "provider" in costruzione. E' irrilevante, dal suo punto di 
vista, che detto provider sia quello che effettivamente contiene la 
risorsa o semplicemente a sua volta la riceva da un'altro provider. In 
altri termini, 
class C implements XProvider {
 public C(XProvider provider) {
  this.provider=provider;
 }
 public X getX() { return provider.getX(); }
}
e' una costruzione tipico - col vantaggio di chiarire al lettore del 
codice che anche C fa uso della risorsa X.
Giusto per annotare, l'unico punto che resta e' l'accesso concorrente - 
usando quest'approccio in un contesto multithreaded, l'owner della 
risorsa dovra' spesso sincronizzarne l'accesso con un lock esplicito.


si, in effetti quello che passo è solo un puntatore, scrivevo "tutta la
classe" perchè dato che in Java
ci sono solo puntatori... cioè passare la classe "per valore" non sarebbe
proprio possibile!
comunque per finire vorrei postare la soluzione che ho trovato, che poi è
proprio quello che stavo cercando (da tempo fra l'altro). Per inciso ho
comprato il libro "Design pattern in Java" che devo ancora leggere e quindi
lo stavo sfogliando per cercare la soluzione...alla fine la Singleton ha
fatto proprio al caso mio (e dire che è l'unico pattern che avevo già
rivisto e l'avevo sempre snobbato :-)
la mia classe principale Applet è diventata Singleton, ed ha un metodo
<public static get> che restituisce l'unica istanza di Applet. La cosa
favolosa è che qualsiasi altra classe, che non ne sa un tubo di Applet, può
sempre chiamare Applet.get e prendersi l'istanza di Applet!!!
Se poi, come suggerisci te, Applet implementa un'interfaccia condivisa anche
meglio perchè è più chiaro quali siano i metodi che deve usare!
interface X {
  public costruisciMappa();
}
class Applet implements X {
 private Applet applet;
 private Voronoi vor;
 public costruisciMappa() {
  // la cosa bella è che questo metodo è public e posso chiamare qualsiasi
metodo!!!
    vor = new Voronoi(mondo.getRobotArea()...);
  }
 main() {
    applet = new Applet;
  }
 public Applet getApplet() { return applet; }
}
class OpzioniVoronoi implements Voronoi {
  public void button_actionPerformed () {
     X x = Applet.getApplet();
    x.costruisciMappa();  // unico metodo di Applet a cui può accedere! et
voilà
 }
}
beh, ovviamente se la classe che ti serve "chiamare" non è unica come in
queso caso (Applet), ma ce ne sono tante, allora credo che serva proprio una
catena (altrimenti a quale istanza andreasti a riferirti?)
grazie ciao

 rivisto e l'avevo sempre snobbato :-)
Ci sono dei problemi di fondo che consigliano in genere cautela
nell'usare singletons. D'altro canto, mi pare che tu stia facendo un
esercizio per imparare, quindi va benissimo: se tutto va bene, parte
del risultato dell'esercizio e' che di questi problemi ti accorgerai -
che e' esattamente il punto. :)