Newsgroup: it.comp.java
Titolo: Per i guru: non fare il mio stesso errore! (con codice)

Ok, ti scrivo anche se me ne vergogno ma ti chiedo comunque un commento.
Immaginiamo di aver il programmatore Tizio e il programmatore Caio che si
occupano di classi di due package dello stesso progetto.
Tizio la classe 'provaCostanti' (in versione 1.0) di utility nella quale
alcune stringhe costanti si occupano ad esempio di memorizzare alcune query
(è soltanto un esempio!).
Caio sfrutta questa classe (2.0) come repository per i suoi algoritmi e
rilascia la sua final release di oggettini sfruttabili a pieno tra i quali
'provaStrana'
Tizio riscrive alcuni pezzi della sua classe 'provaCostanti' (versione 1.1)
modificando delle costanti e compilando.
Il cliente fa girare il sistema ma si accorge che pur essendo utilizzate le
nuove funzionalità della classe 1.1 di Tizio tuttavia sembra che quella 2.0
di Caio veda ancora le costanti vecchie...
Questo accade perchè il compilatore si accorge che le costanti inserite nel
codice sono tali e quindi possono essere direttamente inserite nel codice da
compilare per evitare un 'referencing' alla classe di utility di Tizio...
Sappiate che adesso a spiegarlo sembra un banalissimo errore ma a me ha
portato via un'ora circa di lavoro per capire dove stavo sbagliando.. Poi il
meccanismo di debugging piu semplice del mondo mi ha chiarito le idee: la
System.out... aiutandomi anche, lo ammetto, dal vecchio ma pur sempre comodo
Jad decompiler.
Ciao.
Eccoti il codice semplificato.
// cut here
//classe di Tizio in versione 1.0
package it.javalab.provaPkg;
public class provaCostanti {
  public final static String cost = "Costante in Stringa";
  public provaCostanti() {
  }
}
// cut here
//classe di Caio in versione 2.0
package it.javalab;
import it.javalab.provaPkg.provaCostanti;
public class provaStrana {
  public provaStrana() {
  }
  public void metodo1(){
    String s = "prova somma con " + provaCostanti.cost;
    System.out.println(s);
  }
  public static void main(String[] args) {
    new provaStrana().metodo1();
  }
}
Questa esecuzione scrive  "prova somma con Costante in Stringa"
// cut here
//classe di Tizio in versione 2.0
package it.javalab.provaPkg;
public class provaCostanti {
  public final static String cost = "Costante in Stringa seconda versione";
  public provaCostanti() {
  }
}
Ma questa esecuzione scrive  ancora "prova somma con Costante in Stringa"
(ovviamente se io ricompilo soltanto provaCostanti).
Infatti andando a decompilare provaStrana ottieni il metodo così riscritto:
  public void metodo1(){
    String s = "prova somma con Costante in Stringa";
    System.out.println(s);
  }
Forse è proprio questa la potenza dei final.. Forse ho errato nel volerli
usare, abusandone.. Tuttavia mi sembrava in teoria la cosa più esatta da
fare visto che un attributo final per definizione non modificherà mai il suo
valore.. ma io credevo soltanto in runtime e non anche in compilazione.
Ditemi voi....
--------------------------------
Andrea Musumeci
java programmer free lance
work:           
www.javalab.it
fun&friends: 
www.fauser.it/olimpo76
--------------------------------


Combinazione ne sto parlando in un altro thread con Cristiano, che mi ha fatto ricordare
proprio questo problema.
Il succo comunque e' che non dovresti avere mai attributi privati, comprese le costanti:
in Object Oriented, se lavori in questo modo, violi prima di tutto incapsulazione ed
information hiding e inoltre violi un principio altrettanto importante, l'open-closed
principle (teorizzato da Bertrand Meyer) dal quale deriva appunto questa regola euristica.
Per approfondire puoi leggere direttamente l'articolo:
http://www.objectmentor.com/resources/articles/ocp.pdf
Ciao,
    Bruno.
---
| Bruno Bossola
| A Java Software Engineer :-)
| 
http://digilander.iol.it/bbossola

Per coincidenza la stessa cosa è appena stata fatta notare da Bruno
Bossola (thread "Compilazione Condizionale", Data:2002-03-11 08:41:08
PST).
Se vuoi garantire che a runtime nessuno sovrascriva i tuoi valori
"costanti", puoi fare una classe che carica le tue stringhe da un file
di configurazione, li memorizza in attributi privati ed espone solo
dei metodi get.
ciao
tityrus

Il succo comunque e' che non dovresti avere mai attributi privati, comprese le costanti:
<cut>
...ma nell'esempio di Andrea Musumeci l'attributo (costante) era
pubblico :  public final static String cost = "Costante in Stringa";
č una tecnica utilizzata ampiamente da moltissime classi base di Java,
come ad esempio viene usata Integer.MAX_VALUE (anzichč
Integer.getMaxValue() );
č chiaro che se ipoteticamente si ricompilasse Integer inserendo un
altro valore per MAX_VALUE tutte le classi compilate che riferiscono
tale valore continuerebbero a riferire il vecchio. Ma non per questo
(secondo me) č sbagliato mantenere delle costanti pubbliche in alcune
classi. Basta tenere presente i rischi di errore quando si modificano
le costanti...
Umberto 


E' sbagliato perche' viola incapsulazione, information hiding e un principio di design,
OCP (Bertrand Meyer), che appunto dice che i moduli software devono essere aperti al
cambiamento e chiusi alle modifiche. Il fatto di accettare la presenza di una costante
potrebbe essere assimilabile a quella che si chiama "chiusura strategica", ma se prendiamo
il caso in oggetto francamente avrei preferito che ci fosse un servizio che mi ritornasse
il valore e non direttamente una costante: la complessita' e' uguale (le due parentesi
direi che si possono sopportare :-D), rispetto i principi OO e in piu' sono protetto da un
cambiamento.
