Newsgroup: it.comp.java
Titolo: ottimizzazione classi

ciao a tutti
utilizzo una mia applicazione java per manipolare dati scritti in
mysql.
Ho molte tabelle da gestire e per semplicità di manutenzione ho creato
una classe per ogni tabella che gestisco.
Il main principale alla partenza non istanzia tutte le sopracitate
classi che danno servizi sulle tabelle, ma le dichiara soltanto.
Ogni singola classe di servizio verrà istanziata soltanto la prima
volta che verrà usata (e solo se la userò nell'ambito di una nuova
sessione di lavoro)
esempio:
TabellaUNO tuno;  /* <== definizione della variabile della classe con
cui smanetto la tabella uno */
   /*metoto di servizio "leggiUNO" per usare la classe TabellaUNO */
private  areaUNO leggiUNO(Strint aa) throws Exception {
            /*se prima volta istanzio classe*/
if (tuno==null) tuno=new TabellaUNO ();  	    
            /*lettura areaUNO*/
return tuno.lettura(aa);
}
......
// qui sono nella applicazione e mi serve di leggere la tabella
areaUNO areadati = new leggiUNO("chiave3");  
......
.....
Penso che così facendo il codice risulti ottimizzato, in quanto se nel
database ho 300 tabelle e rurante una sessione di lavoro ne uso
solo 6 o 7, verranno istanziate solo poche classi e non tutte a 300.
Ora però mi sono un po stancato di rispettare questa regola che mi
sono dato, perchè ogli volta che sviluppando il codice mi serve un
nuovo metodo, oltre ad implementare la singola classe di servizio (in
questo esempio in TabellaUNO), devo anche creare un nuovo meto
di servizio che pensi alla eventuale istanza (in questo esempio
leggiUNO)
Volevo farvi queste due domande:
1) se alla partenza istanziassi tutte le 300 classi (anche se poi
magari ne uso solo 6 o 7), sarebbe una bestialità ?
2) sarebbe drammatico richiamare ogni metodo assieme alla istanza ? 
es: new TabellaUNO(this).lettura("chiave aa");
grazie a chi volesse aggiungere le proprie riflessioni
ciao grazie Luciano996

 es: new TabellaUNO(this).lettura("chiave aa");
..un metodo ragionevole, se hai name conventions sufficienti (come pare), 
e' usare la reflection. Assumendo tu abbia tutti i field in this:
public Object leggi(String nomeTabella) {
 Field field = getClass().getField("t"+nomeTabella.toLowerCase());
 Object result;
 if ((result=field.get(this))==null) {
  field.set(result=Class.forName("Tabella"+nomeTabella).newInstance());
 }
 return result;
}
(ho tralasciato l'exception handling per chiarezza)
Se poi tutti i tuoi oggetti discendono da una classe Tabella, puoi 
sostiture Tabella ad Object.

Ciao, luciano996!
Il giorno 09/07/2004 alle ore 15:37 hai scritto:
 l> Ho molte tabelle da gestire e per semplicità di manutenzione ho creato
 l> una classe per ogni tabella che gestisco.
Brivido, terrore e raccapriccio!
 l> Il main principale alla partenza non istanzia tutte le sopracitate
 l> classi che danno servizi sulle tabelle, ma le dichiara soltanto.
AH beh... allora...
 l> Ora però mi sono un po stancato di rispettare questa regola che mi
 l> sono dato, perchè ogli volta che sviluppando il codice mi serve un
 l> nuovo metodo, oltre ad implementare la singola classe di servizio (in
 l> questo esempio in TabellaUNO), devo anche creare un nuovo meto
 l> di servizio che pensi alla eventuale istanza (in questo esempio
 l> leggiUNO)
E ti credo, diamine stai usando un linguaggio ad oggetti, sfruttalo !
Anziche' avere 300 classi perche' non ne crei una sola che si occupi di
gestire in modo trasparente tutte le tabelle (cosa che peraltro fa gia' la
libreria database con Resultset) ? Per esempio potresti sfruttare i metodi
del database per sapere i nomi dei campi della tabella da istanziare, ti
puoi costruire un vettore (o un hashmap che forse e' meglio) con i valori
dei campi e due metodi getValue(field) e setValue(field) che impostano i
valori. Se poi devi per forza avere dei metodi specifici per una o due
tabelle, ti puoi sempre creare una classe che estende quella base.
Se proprio vuoi avere tante classi che dichiarano i campi come variabili (se
uno vuole farsi del male...) puoi usare la reflection per mappare le
variabili ai campi del database ed avere una classe madre che si occupa di
tutto e tante figlie che dichiarano solo i campi del database.
 l> 1) se alla partenza istanziassi tutte le 300 classi (anche se poi
 l> magari ne uso solo 6 o 7), sarebbe una bestialità ?
Rispetto a quello che hai gia' fatto, no.
 l> 2) sarebbe drammatico richiamare ogni metodo assieme alla istanza ?
 l> es: new TabellaUNO(this).lettura("chiave aa");
Dichiaralo statico, tanto bestialita' per bestialita'...
Bye
-- 
There is no emotion; There is peace.
http://www.maccasoft.com

grazie Cristiano e Marco per i vostri prezziosissimi suggerimenti
effettivamente di reflect ho già usato invoke di method,
anche se faccio ancora un po fatica a ragionare per oggetti
purtroppo cose come i vostri esempi, con cui si riesce a generalizzare
molto, nei libri che ho strudiato non ne parlavano quasi per nulla
mi metto a creare una gerarchia di classe Tabelle da cui estendere i
comportamente base, e vedrò con Field come potrò fare a risparmiare.
con le mappe invece vorrei fare cosi:
1) creare una classe che inglobi i comportamenti base che ogni
JInternalFrame del mio desktop deve avere
2) creare al secondo livello (estendendo il primo) alcune mappe tipo
con determinati layout (es:mappa ad elenco, mappa di dettaglio+elenco
ec..)
a questo punto sviluppando  creerò solo mappe di terzo livello che
estenderanno il secondo andando a implementare taluni componenti e
controlli vari che da mappa a mappa sono per forza direvrsi (campi
specifici e controlli)
a questo aspetto tengo molto perchè è questo uno dei motivi per cui
sono passato al java
l'obiettivo è ottimizzare al massimo lo sviluppo visto che i clienti
non lo capiscono quanto tempo ci vuole a fare il software, mentre
capiscono meglio il tempo gli imbianchini (purtroppo devo mangiare
altrimenti li lascierei schiattare con excel).
a tale proposito (mappe) avete qualche suggerimento ?
grazie ancora ciao

Cristiano, con la reflection si riesce a fare una nuova istanza
partendo dalla variabile di classe ?
mi spiego meglio; vovveri fare così (e non mi riesce):
....variabili di mie classi
Mia1 m1;
Mia2 m2;
.......
.....nel codice
avvia(m1);
......
avvia(m2);
protected void avvia(Object xx) {
...
?????non so come fare=> vorrei che questo metodo faccia: 
xx.newInstance("parametro");
}
questo per fare un metodo che instanzi le classi Mia2 Mia2
ecc..(accettano tutte lo stesso parametro nel costruttore per ora)
in questo metodo infatti ho messo del codice che verifica se la classe
è già attiva (ciclando tra quelle attive grazie a getClass().getName()
) ed chiedere all'utente se ne vuole aprire un'altra; quindi in caso
affermativo la deve istanziare
Ma accade anche che la prima volta l'oggetto è null e dovrei comunque
instanziare la classe (senza avere un aggetto su cui lavorare)
grazie ciao

 mi spiego meglio; 
Pardon, non ho capito. :)

...

mi spiego meglio
nell'esempio che ho fatto, il metodo "avvia" viene invocato
passandogli il riferimento a oggetti che in realtà non sono ancora
oggette in quanto non inizializzati
vorrei che "avvia" possa creare una nuova istanza della variabile che
gli viene passata; nell'esempio il metoto accetta Object, anche se
credo non vana bene (forse class ?)
grazie ciao

 credo non vana bene (forse class ?)
*Se* quanto vuoi fare e'
Object obj=null;
avvia(obj); 
..ti aspetti che obj sia diverso da null.. 
non si puo': i parametri in java sono passati per valore. 
Con la reflection, potresti scrivere:
void avvia(String nomeMembro, String nomeClasse) {
  // Crea un'istanza di nomeClasse (usando il default constructor)	
  Object obj = Class.forName(nomeClass).newInstance();   
  // Trova l'oggetto Field relativo al membro di nome 
  // "nomeMembro" in this
  Field field = getClass().getField(nomeMembro);
  // Assegna il membro con l'istanza appena creata
  field.set(obj);  
}
ma e' un'idea da Ufficio Complicazione Cose Semplici. :)
Se tutto quello che ti serve e' creare oggetti e dargli un nome, perche' 
usare membri? Usa una Map come membro, invece -  che ti permette di 
mantenere le varie istanze e accedervi "per nome":
private Map tabellePerNome = new HashMap();
public void creaTabella(String nomeTabella) {
  // Determina il nome della classe associata alla tabella
  String nomeClasseTabella = "com.luciano.tabelle."+nomeTabella;
  // Crea l'oggetto tabella adatto
  Object obj = Class.forName(nomeClasseTabella).newInstance();
  // ..e mettilo nella mappa, usando il nome della tabella come chiave
  tabellePerNome.put(nomeTabella, obj);
}

Cristiano, ti ringrazio tantissimo per il tempo che mi hai dedicato.
C'era questa cosa che mi hai spiegato che non avevo capito.
Ovviamente poi, come consigliato anche da te, ho scelto la strada piů
semplice, cioč istanziare gli oggetti direttamente dalla variabile di
classe, e me li sono memorizzati in un Vector per poterli
riutilizzare.
Li riprendo come oggetti ed invoco i metodi standard usando la invoke.
in questo esempio vedo se l'oggetto ha un metodo
"setRichiestaChiusura", e se ce l'ha lo invoco passando un parametro
boolean "catena" (non ti dico quanto tempo ci ho messo a farlo
funzionare...ma cosě dal mio desktop chiedo servizi a tappeto a tutti
gli internal frame, senza sapere che classi sono)
try{
  Object o1 = finestre.get(i);  //Finestre č Vector
  Class c2 = o1.getClass();
  Method[] methods = c2.getMethods();// getDeclaredMethods();
  for (int k = 0; k < methods.length; k++) {
    Method m = methods[k];
    String name = m.getName();
    if (name.indexOf("setRichiestaChiusura")!=-1) {
      m.invoke(o1, new Object[]{ (Object) new Boolean(catena) })
    ;
  }
}catch...
Dovrebbe andare bene no? anche se non ho usato il map che non
conoscevo
grazie ancora a presto, ciao

 Dovrebbe andare bene no?
Ok, adesso arriva un trucco: non c'e' bisogno della reflection per invocare 
il metodo setRichiestaChiusura(). Se *sai* che il metodo c'e', basta:
 - dichiarare un'interfaccia X che contiene setRichiestaChiusura(boolean)
  public interface X {
    public void setRichiestaChiusura(boolean v);
  }
 - aggiungere "implements X" alle tue varie classi-tabelle
  public class TabellaUno extends Tabella implements X { ... }
 - Usare X come tipo invece di Object:
   X o1 = (X) finestre.get(i);
   o1.setRichiestaChiusura(catena);
 Il trucco e' che il tipo dinamico della classe creata con newInstance() 
contiene X, quindi il cast a X alla prima linea sopra e' corretto.
(per "tipo dinamico" e "tipo statico" cerca nei post passati con google).

 (per "tipo dinamico" e "tipo statico" cerca nei post passati con google).
porcap...., e io che ci avevo messo non sai quanto a studiarmi la
reflection
(comunque non mi ha fatto male di sicuro)
mi sa di tarocco, come di te, ma č grandioso!!!
Questo esempio cade proprio a fagiolo, perchč (EUREKA!!)sono riuscito
finalmente a fare quello che dicevo; come dicevo devo assolutamente
risparmiare sui tempi di codifica delle mappe, e cosě ho creato la mia
prima catena:
1) classe IFBase 
che contiene i metodi con cui ogni JInternalFrame dialoga con il
desktop (come il setRichiestaChiusura sopra...)
2) classe IFlay1 che estende IFBase 
contiene un tipo di layout tipo e tutto quello che serve per gestire
gli spostamenti del cursore e l'attivazione dei pulsanti di comando
3) classe xxxx  che estende IFlay1
č la mappa vera e propria, ma finalmente qui dichiaro solo i singoli
componmenti (etichette, campi e bottoni) e chiedo alla classe opra di
attaccarli al layout
delle classi di liv.2 ne farň forse 6 o 7, mentre farň molte classi
xxxx, ma senza peoccuparmi di nulla, scelgo il layout di liv.2 che piů
si addice al dialogo che devo instaurare con l'utente (taccagno) e mi
metto a creare solo i singoli campi
con questa generalizzazione risparmierň moltissimo (mi sono posto come
obiettivo non piů di un ora per fare una nuova mappa)
arrivo alla domanda:
dal tuo esempio desumo che posso creare "interface" e quindi
implementarle nelle classi xxxx per potervi includere metodi di
comportamento ripetitivi (ovvero che devono stare in ogni casse che
implementa l'interfaccia) ?
sono una sorta di Include di altri linguaggi !? possono contenere
anche variabili ?
grazie (ho imparati piů cose interessanti qui, che sui due libri che
ho letto; facevano solo esempi di basso livello, ed invece di classi
ce ne sono una marea, ed interfacciarsi con la tastiesa č un disastro)

 ce ne sono una marea, ed interfacciarsi con la tastiesa Š un disastro)
Guarda, dal tipo di domande che fai, pero', mi par che ti manchino proprio 
le basi dell'object orientation; e usare Java senza quelle, e' come 
costruire un grattacielo senza sapere nemmeno di calce e mattoni - 
fattibile ma ci metti una vita, il risultato sara' certamente non troppo 
buono e probabilmente crolla al primo refolo di vento.
Ti consiglio una buona introduzione all'OO e ai suoi concetti. 
Sfortunatamente, non so darti troppi consigli in proposito perche' la mia, 
di introduzione, la lessi circa 15 anni fa :-) (e dubito che "OOP in C++" 
ti serva a qualcosa oggidi'). Prova a cercare in post passati.

 ti serva a qualcosa oggidi'). Prova a cercare in post passati.
si certo è proprio così, mi mancano basi forti di oop, anche se
culturalmente ragiono ad oggetti (ho 19anni di esperienza) nonostante
che per estrazione parta sempre a ragionare dalla formula
"informazioni+processi" e gli oggetti cerco di descriverli per
mantenere congruente quanto realizzo.
Mi resta difficile implementare le cose; anche se mi ci sono messo di
buona lena a studiare, perfino qualcusa di specifico sull' OOP.
Ma un conto è studiare ed un conto è implementare; quello che mi
incasina è che spesso mi aspetto di un oggetto di trovare solo metodi
e proprietà ed una sola dipendenza, ed invece in java ci sono delle
cose ingarbugliate con le classi che una ne tira un'altra che a volte
ne perdo il filo (vedi i jcomponent dello swing), eppure uso molto il
Tutorial di sun.
Comunque ora mi sono messo anche a "fare", se no non fisnisco mai di
studuare.

Cristiano, approfitto ancora della tua competenza.
Ho una classe che ha dei metodi public; è possibile in un metodo di
tale classe sapere qual'è l'oggetto "tipo" che sta richiamando questo
metodo ?
(è una porcheria, perchè di fatto un metodo dovrebbe dare lo stesso
servizio a tutti, però mi incuriosisce sapere se è possibile)
ciao grazie.

 Cristiano, approfitto ancora della tua competenza.

Si e no. Nel senso che e' una porcheria :-), richiede un trucco che abbatte 
le prestazioni e la semplice idea ha "cattivo design" scritto in lettere 
cubitali rosse in flash :)
Il trucco e' semplice: sollevi un'eccezione fittizia e guardi nella linea 
corretta dello stacktrace.
try {
 throw new Exception();
} catch(Exception e) {
 StringWriter sw=new StringWriter();
 PrintWriter pw = new PrintWriter(sw);
 e.printStackTrace(sw);
 String trace = sw.toString();
 ..esamini trace...
}
Con JDK1.5 hanno introdotto un meccanismo di instrumentazione, ma ancora 
non l'ho visto nei dettagli quindi non so se c'entra.