Newsgroup: it.comp.java
Titolo: Aiutino

public MyApp()
	{
		this.addWindowListener	(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				dispose();
				System.exit(0);
			}
		});
	}
Devo dire che molte cose di questo listato mi appaiono misteriose e
non so dove andare a reperirle visto che sul mio manuale non son
presenti.
La seconda riga ad esempio non la comprendo. Non conosco il metodo
addWindowListener ne WindowAdapter.
Non conosco il metodo WindowClosing e non capisco cosa sia dispose().
Tuttavia ho capito che è un metodo veloce per gestire l'evento di
chiusura di una finestra e quindi vorrei capirlo.
Se qualcuno avesse la pazienza avrebbe anche la mia gratitudine :)
"I want to know God's thoughts....
....the rest are details"

 }
Per capire questo listato devi conoscere un paio di cose: le inner classes e
gli eventi del JDK 1.1. Allora, con ordine...
Le inner classes sono classi innestate le une dentro le altre. Prendi
l'esempio seguente:
public class MyClass {
  private class MyInnerClass {
    public void go() {
      // Fa qualcosa...
    }
  }
  // Fa qualcosa che usa la classe MyInnerClass
}
Qui la classe MyInnerClass è dichiarata internamente alla classe MyClass.
Questo significa che solo MyClass la conosce e la può utilizzare. Nessuna
inner class può essere dichiarata pubblica. Servono, in sostanza, ad
avvolgere dati o funzionalità in classi per pura comodità della classe che
li deve utilizzare, ma non per le altre classi del package o
dell'applicazione.
Quella riga criptica relativa all'addWindowListener() fa esattamente questo:
crea una inner class. La stessa cosa avrebbe potuto essere scritta così:
public class MyApp {
  private class  MyWindowAdapter {
    public void windowClosing(WindowEvent e) { /* ... */ }
  }
  // [...]
    addWindowListener(new MyWindowAdapter());
  // [...]
}
Il window adapter, nel tuo esempio, viene dichiarato e istanziato nella
stessa istruzione. Java ti permette di farlo, per risparmiare tempo e
codice, ma in effetti è un po' criptico da leggere. Nell'esempio qui sopra
sono sottointese delle cose: ad esempio dispose() è un metodo locale di
MyApp, quindi la MyWindowAdapter, per poterlo invocare, avrebbe bisogno di
un puntatore (che andrebbe passato nel costruttore). Comunque il risultato e
il significato è lo stesso.
Per quanto riguarda gli eventi, bisogna che tu entri un attimo in come
funziona la loro l'architettura dal JDK 1.1 in avanti. Ogni classe in grado
di "emettere" eventi ha una lista di altre classi che lo devono ricevere.
Queste classi sono dettere "listener" (cioè ascoltatori) e devono
implementare una specifica interfaccia per poter essere utilizzate. Gli
adapter non sono altro che classi che implementano l'interfaccia di ascolto
di un determinato tipo di evento. Quindi, in sostanza:
public interface WindowListener {
  public void windowClosing(WindowEvent e);
}
public class WindowAdapter implements WindowListener {
  public void windowClosing(WindowEvent e) {}
}
Se tu estendi il WindowAdapter e reimplementi il metodo windowClosing() in
pratica costruisci una classe capace di reagire agli eventi di tipo
"finestra" (ed in particolare all'evento di chiusura della finestra) e che
può essere "iscritta" tra gli ascoltatori di eventi di una determinata
finestra. Il metodo addWindowListener() fa proprio questo: aggiunge un
classe ascoltatore alla lista degli ascoltatori di eventi di tipo "finestra"
di una determinata finestra.
Ricapitolando... Hai una finestra, si chiama MyApp, e vuoi che si termini
all'evento di chiusura della finestra. Crei un adapter con una inner class
che invoca la dispose() (terminazione) dela finestra all'evento di
windowClosing. Poi iscrivi l'adapter tra gli ascoltatori di eventi della
finestra MyApp. A questo punto quando qualcuno preme il pulsante di chiusura
della finestra MyApp, questa genera l'evento e scorre la sua lista di
ascoltatori. Ne trova uno solo, il tuo adapter, sul quale invoca la
windowClosing() passandogli l'evento generato. Il tuo adapter reagisce
chiamando la dispose() e il gioco è fatto.
Un'ultima cosa. Gli adapter creati così in linea, come è nel tuo listato, si
chiamano "anonymous adapter", proprio perchè sono inner class senza nome (in
quanto non dichiarate esplicitamente, come invece è nel listato alternativo
che ti ho scritto più sopra). Quando vai a compilare, il javac ti produce
due file .class: MyApp.class e MyApp$1.class. Il secondo è il tuo adapter,
battezzato d'ufficio "1"... Tutto qui.
Spero di esserti stato d'aiuto. Ciao.
   Gianlu

dell'applicazione.
Ovviamente, anche questa conseguenza non vale :)
In effetti una pratica che ho trovato avere ottimi risultati e' dichiarare 
interfacce per comportamenti specifici ad una classe come inner interfaces 
pubbliche. In tal modo, nel codice chiamante risulta immediatamente chiaro 
a che cosa ci si sta riferendo. Faccio un esempio, dato che e' una tecnica 
di design che mi piace molto:
Supponi di avere molte classi 'client di rete'. Tutte quante richiedono un 
oggetto che 'validi' il login. Uno schema utile e' il seguente:
interface GenericValidator { 
  ...metodi...
}
public class Client1 {
 public interface Validator extends GenericValidator {
  ....metodi...
 }
 public class StandardValidator implements Validator {
  ...implementazioni...
 }
}
 
public class Client2 {
 public interface Validator extends GenericValidator {
  ....metodi...
 }
}
...etc...
Client1 c1;
Client1.StandardValidator c1sv = c1.new StandardValidator();
.....
questo codice permette a chi lo legge di capire allo stesso tempo che 
'StandardValidator' ha un ruolo generale ma e' un'implementazione speciale 
per un certo tipo di Client. Fornendo in modo compatto piu' informazioni, 
lo trovo piuttosto elegante.
-- 
God is Real, unless declared Integer.
ObjectZone - 
http://space.tin.it/computer/csadun/

 (sorry, ma come ti chiami?) che e' anche
l'opinione che ho sempre visto espressa nei pochi testi che ho avuto
tempo di leggere e che ho utilizzato nei progetti che ho seguito.
Questo ovviamente non vuol dire che sia in disaccordo con un uso
diverso o + smart delle inner classes, ben venga anzi! Solo che secondo
me ne costituisce un uso poco comune.

Brrr! Decisamente non condivido: la sintassi e' veramente urfida! ;-)
Si vede che hai usato parecchio il C++ :-)
Decisamente preferisco inserire un metodo nella classe client
getValidator() che si occupa lui di effettuare l'istanza, dichiarando
costestualmente protected/friendly/private l'inner class relativa,
eventualmente specializzata, incapsulando quindi completamente
l'implementazione.
Ciao,
      Bruno.
--
Bruno Bossola, a Java Developer
Sent via Deja.com 
http://www.deja.com/
Before you buy.

l'implementazione.
Naturalmente. Pero' tieni presente che l'esempio era giusto un accenno, breve 
per motivi di spazio, e non ho citato i requirements associati a quel 
particolare design: ad esempio, quando stai disegnando un framework, il goal e' 
di fornire comportamenti standard facili da usare immediatamente; e allo stesso 
tempo fornire al framework flessibilita' sufficiente per essere esteso/adattato 
quanto basta e quando serve. Il tutto, preservando per quanto possibile la 
leggibilita' del sorgente e incoraggiando quella del codice chiamante.
Ora, la strada che segui e' quella giusta (e certamente ce lo metto anch'io il 
metodo di factory): ma risolve solo il primo requirement. 
Esporre l'interfaccia ed eventualmente la classe di implementazione standard 
aumenta la riusabilita', permettendo al codice utilizzatore di comprendere 
meglio l'object model esposto dal componente/framework, e di usarlo o derivare 
in caso di necessita' specifiche - naturalmente solo quando vuole farlo.
Il fatto che la classe sia inner le da' una *qualita* diversa nel design - 
l'utente e' guidato a capire che l'uso di quella classe/interfaccia e' legato 
all'uso di quella contenitrice. Avere invece solo interfacce al "primo livello" 
non suggerisce alcuna distinzione tra esse e le relazioni vanno cercate in 
documentazione (se e' scritta, aggiornata e il programmatore ha voglia di 
leggerla). 
Tipico esempio - gli StreamHandler, creati in 1.0. Sono *strettamente* legati 
alla Factory relativa e agli URLConnection, ma nel design (intendo, le 
interfacce pubbliche esposte da classi/interface) non c'e' quasi traccia di 
questo - perche' Java 1.0 non aveva i costrutti necessari. Un po' meglio nella 
documentazione, che pero' soffre - come sempre - di vecchiaia e problemi di 
aggiornamento.
Infine, la leggibilita'. In effetti io di solito definisco l'implementazione 
standard di un'interfaccia inner all'esterno se voglio enfatizzare il riuso, e 
all'interno se voglio enfatizzare la "pluggabilita'". :) 
In questo modo chi usa il framework vede cose del tipo
 class XXX implements Classe.Interfaccia
che a me piacciono - rendono chiaro (anche in documentazione autogenerata) che 
una classe implementa un'interfaccia specifica per *quella* classe.
Codice come Client.Validator v = client.new Validator() ti sembra strano la 
prima volta, ma ti ci abitui (e i tuoi programmatori con te) dopo un minuto... 
e inoltre li usi solo quando servono e stai facendo un lavoro speciale 
estendendo o modificando il comportamento standard della classe. 
E che suoni un po' strano a me fa piacere - so che gli sviluppatori ci si 
fermeranno un attimo di piu'.. "suona" particolare perche' *e'* (un uso) 
particolare. :)
Inoltre - ma questa e' una cosa che piace a me :) - lo spazio dei nomi viene 
partizionato ancora meglio: package.Classe.Interfaccia mi fa capire al volo che 
Interfaccia si usa nel contesto di Classe nel contesto del Package. :)
Per non fare un trattato, concludo.. prendi ad esempio il modello ad eventi 1.0 
e quello 1.1. Certamente l'1.0 e' piu' leggibile e semplice (ricorda come ti e' 
parso l'1.1 la *prima volta* che l'hai visto.. ;-) - tuttavia quel design non 
soddisfa alcuni goal che sono necessari nel contesto della gestione degli 
eventi GUI. Ed ecco l'1.1 - un po' meno leggibile (non troppo, ci si abiuta 
presto :) ma molto piu' efficace. 
Come tutti i pattern, quello sopra nasce per soddisfare dei requirements: se 
non li hai, resta inteso, lo puoi tranquillamente ignorare. :)


 wrote:
Bhe, non posso fare altro che ringraziarti e fare tesoro di quello che
hai scritto.


 tranquillamente ignorare. :)
Per chiarezza che ne dici di postare un semplice esempio pratico in cui
risulterebbe necessario l'uso del tuo approccio per soddisfare i
requirements di cui sopra? Se mi convinci, prometto che appena ci
vediamo ti offro un caffe'!


vediamo ti offro un caffe'!
LOL ho messo qualche esempio in questo articolo. Se vuoi piu' dettagli,  l'uso 
del framework di listening asincrono di eventi che trovi sul mio sito si presta 
perfettamente a quel tipo di pattern (anche se ovviamente e' usabile anche 
senza). Non ricordo se nella guida ho messo un'esempio in quel senso, se non 
c'e' te lo faccio subito. 
Per il caffe' - se vengo giu' in Italia te lo offro io piu' che volentieri... 
qui un buon caffe' non sanno nemmeno che cos'e'. :)


volentieri... qui un buon caffe' non sanno nemmeno che cos'e'. :)
Beh, ma mi porto la moca + il lavazza, ovviamente! Il gas li' ce
l'avete? Altrimenti mi posso attrezzare con un fuocherello
in salotto ;-D
Ciao,


in salotto ;-D
Vedi: hai centrato il problema... qui hanno le piastre elettriche! Dimmi tu 
come si fa a cucinare come si deve, con le piastre elettriche.. ;-)
Ciao,
 -cs
