Newsgroup: it.comp.java
Titolo: "public final " o private con metodi accessori???

Salve,ho dei campi di una classe che potrebbero essere visibili a tutti
ma comunque non possono essere modificati:è più corretto dichiarali
public final oppure private e utilizzare metodi accessori?
Grazie
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 ha scritto nel messaggio
news:9fe309b5dc85bc2ffe4...@mygate.mailgate.org...


 public final oppure private e utilizzare metodi accessori?
Secondo me la seconda. Come scelta in generale le variabili di istanza
devono essere private ed essere accessibili con metodi getter e setter.
Questo poi mi sembra proprio il caso adatto visto che puoi limitare
l'accesso scrivendo solo il metodo get. Se poi per qualche ragione di
design quella variabile _non deve_ cambiare allora la dichiari final. Ma
mettere final per impedire di modificarla dall'esterno non mi sembra molto
corretto.
Ciao
Matteo
-- 
chi sono e soprattutto chi non sono:
http://www.ilnomedeldominio.it
un piccolo programma per studenti universitari:
http://inutility.ilnomedeldominio.it/imsv/

 > ma comunque non possono essere modificati:č piů corretto dichiarali


 public final oppure private e utilizzare metodi accessori?
Il punto e':
*potrebbero* o *devono* essere visibili?
non possono essere modificati *dall'esterno* o *dall'interno* della classe?
Se i campi non possono essere *mai* modificati ma *devono* essere visibili
dall'estrerno allora li puoi dichiarare con "public final".
Se i campi non possono essere *mai* modificati e *non devono* essere
visibili dall'estrerno allora li puoi dichiarare con "private final".
Se i campi possono essere modificati e devono essere visibili dall'estrerno
allora li puoi dichiarare con "private" aggiungendo il metodo "get" per
prelevare il valore ed eventualmente il metodo "set" per settarlo.
-- 
Marco "Duff" Palermo
http://www.marcoduff.com/

 i campi non possono essere *mai* modificati ma *devono* essere visibili
 dall'esterno...


  dall'esterno...
Allora dichiarali come public final.


 Allora dichiarali come public final.
io aggiungerei pure static
MArco

 
stai scherzando? non sono statici,che c'entra?


 
C'entra parecchio;
essendo una costante(final) se la dichiari statica risparmi sulla memoria(se 
esistono 2 o più istanze della classe "vive" in memoria; ma cmq è buona prassi 
anche se ne esiste solo una).
Tipo.. Color.BLACK, mai usato?
Mettiamo che nella tua classe dichiari
     public final int LA_MIA_COSTANTE = 1;
e crei 2 oggetti dalla classe; i 2 oggetti allocheranno entrambi in memoria 
l'int, nonostante il valore non possa mai cambiare. Uno spreco.
Facendo invece
     public static final int LA_MIA_COSTANTE = 1;
indipendentemente da quanti oggetti crei, in memoria esisterà una sola istanza 
della tua variabile a cui tutti gli oggetti creati dalla tua classe faranno 
riferimento(si chiama anche class variable) e vi si accede tramite
     int temp = MyClass.LA_MIA_COSTANTE;
L'unica cosa a cui prestare attenzione è che si tratti di un tipo primitivo o di 
un riferimento ad un oggetto immutabile(ad esempio String).
Fare una cosa del genere
     public static final int[] troubles = new int[] {1,2,3};
significa cercare guai.. ;)
Marco
P.S. in realtà non è la soluzione migliore, esiste il typesafe enumeration 
pattern, ma questa è un'altra storia(gratis dalla 1.5 ;)
-- 
reply: remove duh.spam.
http://javac.imap.cc

 essendo una costante(final)
Humz, ma dove?, come non detto, ho sparato una boiata immonda.
Mi ero scordato le variabili d'istanza blank final...
Ora che sono rinsavito :), per tornare al soggetto del post, la "rule of thumb" 
dice che a parte campi static final le classi pubbliche non devono avere campi 
pubblici, dunque nel tuo caso si usa un metodo accessorio.
Marco


 pubblici, dunque nel tuo caso si usa un metodo accessorio.
Scusami ma non ti seguo...
Chi ha detto che classi pubbliche non possono avere campi pubblici?
Due su tutti java.lang.System.out e java.awt.Point.x (il primo final il
secondo no)!!!


 secondo no)!!!
Lo dice Joshua Bloch nel suo libro(effective java) :)
<quote>
To summarize, you should always reduce accessibility as much as possible. After 
carefully designing a minimal public API, you should prevent any stray classes, 
interfaces, or members from becoming a part of the API. With the exception of 
public static final fields, public classes should have no public fields. Ensure 
that objects referenced by public static final fields are immutable.
</quote>
Come ho detto, la prendo come "rule of thumb" anche se devo ammettere di non 
aver capito esattamente la sua giustificazione; gia che ci sono la aggiungo e 
magari qualcuno me la spiega ;)
<quote>
Even if a field is final and does not refer to a mutable object, by making the 
field public, you give up the flexibility to switch to a new internal data 
representation in wich the field does not exist.
</quote>
Piů che altro non riesco ad immaginarmi un esempio pratico..


 Più che altro non riesco ad immaginarmi un esempio pratico..
Sulla limitazione dei campi public ci siamo.
L'esempio piu' banale e' in una variabile tipo
public int divisore;
che non deve mai essere 0.
Meglio dichiararla private e creare un metodo tipo:
public void setDivisore(int d) {
   if(d!=0) divisore=d;
}
o, in un altro esempio, se una variabile puo' assumere una dato valore (o
puo' mutare il proprio valore) soltanto in particolari condizioni. In
questo caso il metodo setX(...) diventa qualche cosa di complesso.
Ma se quella variabile non ha alcuna limitazione e non e' legata a nulla
(vedi java.awt.Point.x) non vedo il motivo di non renderla pubblica e
risparmira righe di codice per dei banalissimi setX e getX!
Per quanto riguarda la spiegazione di Mr. Joshua Bloch credo che si sia
fumato paprica messicana comprata da un venditore di broccoli quando ha
dettato quella frase alla sua segretaria isterica che in quel momento
parlava al telefono con l'amante mentre aveva in attesa di chiamata il
marito!
Meglio se da una occhiata all'errore di compilazione: "cannot assign a
value to final variable x".


 value to final variable x".
Non ho capito il nesso..


 </quote>
In questa frase mi sembra di capire che se tu hai una variabile final e la
rendi pubblica tu dai la possibilita' di poter cambiare la sua
rappresentazione interna nella quale il campo non esiste.
Ma questo e' inesatto.
Se ho una variabile
public final int x;
anche se ho dichiarato la variabile public io NON posso cambiare il suo
valore e quel valore DEVE esistere.
Forse traduco male io o non riesco a comprendere quello che vuole dire
l'autore o mi serve il resto del contesto. Ma da come la percepisco io mi
sembra alquanto inesatta come frase.


 rappresentazione interna nella quale il campo non esiste.
Hmm, no, non è questo che intendeva.
Lui dice che rendendo la variabile finale pubblica ti precludi la possibilità, 
un giorno, di modificare la struttura dati della classe(e la modifica in 
questione sarebbe eliminare la suddetta variabile).
Provo ad azzardare un esempio, non so quanto pertinente
Prima release(la variabile birthYear viene usata sia internamente sia esternamente)
----------------------------------------------------------------------
/*** 1.1) Soluzione public final ***/
public class LifeInsurance {
   public final int birthYear;
   public LifeInsurance(int birthYear) {
     this.birthYear = birthYear;
   }
   private int computeAge() {
     return Calendar.getInstance().get(Calendar.YEAR) - birthYear;
   }
   public int computeLifeInsuranceAmount() {
     return computeAge() * 100;
   }
}
/*** 1.2) Soluzione getter ***/
public class LifeInsurance {
   private final int birthYear;
   public LifeInsurance(int birthYear) {
     this.birthYear = birthYear;
   }
   private int computeAge() {
     return Calendar.getInstance().get(Calendar.YEAR) - birthYear;
   }
   public int computeLifeInsuranceAmount() {
     return computeAge() * 100;
   }
   public int getBirthYear() {
     return birthYear;
   }
}
Seconda release(3 mesi dopo; i tuoi colleghi hanno fatto un po di refactoring e 
ora ti viene passato l'età al posto dell'anno di nascita; la variabile birthYear 
viene utilizzata solo esternamente)
--------------------------------------------------------------------------------
/*** 2.1) Soluzione public final ***/
sei fottuto; o ti tieni la(ormai ridondante) variabile pubblica e calcoli l'anno 
di nascita nel costruttore o fai un getter e devi andare a cercare tutti gli 
utilizzatori della classe test e modificare la chiamata.
public class LifeInsurance {
   public final int birthYear;
   private final int age;
   public LifeInsurance(int age) {
     this.age = age;
     birthYear = Calendar.getInstance().get(Calendar.YEAR) - age;
   }
   public int computeLifeInsuranceAmount() {
     return age * 100;
   }
}
/*** 2.2) Soluzione getter ***/
public class LifeInsurance {
   private final int age;
   public LifeInsurance(int age) {
     this.age= age;
   }
   public int computeLifeInsuranceAmount() {
     return age * 100;
   }
   public int getBirthYear() {
     return Calendar.getInstance().get(Calendar.YEAR) - age;
   }
}
Come vedi nel secondo caso è possibile modificare la struttura interna 
elegantemente mentre nel primo no. Va da se che se hai in mano tutto il codice e 
un ide con un minimo di supporto di refactoring il primo caso lo correggi in 
qualche secondo; se però ti trovi in una situazione dove gli utilizzatori della 
classe LifeInsurance si trovano sparsi chissà dove in chissà quali programmi non 
puoi permetterti di eliminare la variabile pubblica senza creare ..hmm.. il caos :)
Marco
p.s. il bello di queste discussioni è che mi costringono a pensare ;-)


 chiamata.
si legge
a cercare tutti gli utilizzatori della classe LifeInsurance e modificare la 
chiamata.
:P


 
Senza contesto non sono certissimo, ma par riferirsi al semplice fatto
che esponendo una costante primitiva via nome (public final) puoi cambiarne 
il valore (internal data repr.) e il codice client, ricompilato, non 
risentira' della differenza dato che si riferisce al valore per nome.
-- 
You dont know what to do when you dont know what you're doing.
http://space.tin.it/computer/csadun

 questione sarebbe eliminare la suddetta variabile).
[CUT]
Adesso mi e' piu' chiaro quello che voleva dire l'autore, ma
sfortunatamente non ho cambiato la mia idea!!!
Quello che vuole dire l'autore e' giustissimo, ma sfortunatamente si
applica a *tutte* le cose dichiarate public, sia costanti che variabili che
metodi!
Un metodo pubblico (per restare compatibile al 100%) *non* puo' essere
aggiornato a casaccio! Deve conservare alcune proprieta' quali gli
argomenti passati e il valore restituito con lo *stesso* significato
dell'originale.
Quando si ci trova d'avanti una variabile "primitiva" (non intendo un tipo
primitivo!) i metodi di get e set non fanno e non *faranno* nulla di
diverso di un "return x" o di un "this.x=x".
Quando si aggiorna un metodo di solito si cambia l'algoritmo interno, non
l'interfaccia. Nel caso di un metodo "primitivo" *non* esiste algoritmo!
Sarebbe assurdo (anzi *grave*) avere una classe con un metodo
getBirthYear() che nella versione 1.0 mi restituisce la data esatta di
nascita e che nella versione 1.1 mi restituisce i secondi passati dal 1900
alla data di nascita! In questi casi si cambia il metodo e quindi la famosa
"internal data" dell'autore.
Se fosse vero non avrebbe neanche senso parlare di variabili o costanti
pubbliche, sarebbe un bug del compilatore java non dare errore di
compilazione quando si dichiarano variabili pubbliche!
Non avrebbe senso avere una java.awt.Point.x o una java.lang.System.out
pubbliche!
Quindi come si cambia l'"internal data" per una variabile e' probabile che
si cambia anche per un metodo. Non a caso in Java esistono i metodi
deprecati! Il tuo e' un bell'esempio, ma non e' reale! Nessuno si sogna di
fare quel grosso cambiamento in un solo colpo... Passano almeno 5-6
versioni con la bella scritta deprecated nella documentazione!
N.B.
Attenzione: dopo questa lunga spiegazione non vorrei buttare la moda del
"public libero".
E' giustissimo il pensiero a monte dell'autore e che, spero, pensiamo
tutti: "Tentare di ridurre al massimo i metodi pubblici in favore dei
privati". Questo per motivi di maggiore leggibilita' della documentazione
e, quindi, per un facile utilizzo ed aggiornamento del codice.


 versioni con la bella scritta deprecated nella documentazione!
I metodi deprecati servono quando si cambia l'interfaccia pubblica di
una classe e sono una ***documentazione*** (non li considererei
strettamente parte del linguaggio) che dice "attenzione, si sconsiglia
di usare questo metodo).
Andrea


 diverso di un "return x" o di un "this.x=x".
In effetti hai parzialmente ragione. I getter/setter (o accessors) 
rompono l'incapsulamento. Fino a qualche mese fa mi toccava spiegare un 
sacco di cose, da poco A.Holub ha scritto un articolo sul quale ho molto 
poco da aggiungere:
http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
buona lettura
uL

 valore in tale modo.
[MEGACUT]
Alt! Forse mi sono spiegato male e non ho fatto intendere bene il mio
ragionamento. Lo espongo di nuovo in una semplice frase: "E'
*consigliabile* usare meno metodi-variabili-costanti pubbliche in un
listato, ma esistono delle *eccezioni*. Il fatto che sia *consigliabile*
usare poco la parola *public* non significa che questa non *deve* o che sia
un *errore* usarla. Ripeto come esempio java.awt.Point.x. Mettere questa
variabile come private e usare i get e set e' un *inutile* passo."
Tutto quello che dici e' giusto, ma non fai altro che rafforzare il mio
discorso! Ripeto, non voglio dire di usare *sempre e comunque* public, anzi
voglio dire che in *alcuni* e (magari) *rari* casi e' comodo usarli.
