Non ti manca nulla. Ciò che fai dipende interamente dalla tua situazione. Tuttavia, considera questo:
È molto comune eseguire la convalida dei parametri in un setter.Per esempio, diciamo che ho una classe con il campo che può contenere un valore da 0 a 10 (il "getta" non è necessario per l'eccezione di tipo sotto, ma ho includerlo per chiarezza):
public class Example {
private int value;
public Example() {
}
public final int getValue() {
return value;
}
public final void setValue (int value) throws IllegalArgumentException {
if (value < 0 || value > 10)
throw new IllegalArgumentException("Value is out of range.");
}
}
Qui, setValue () convalida il "valore" per assicurarsi che rispetti le regole. Abbiamo un invariante che afferma "un Esempio non esiste con un valore fuori dall'intervallo". Ora diciamo che vogliamo creare un costruttore che abbia un valore. Si potrebbe fare questo:
public class Example {
...
public Example (int value) {
this.value = value;
}
...
}
Come potete vedere, c'è un problema. La dichiarazione new Example (11) avrebbe avuto successo, e ora esiste un Esempio che infrange le nostre regole. Tuttavia, se usiamo il setter nel costruttore, possiamo comodamente aggiungere tutti convalida dei parametri al costruttore così:
public class Example {
...
public Example (int value) throws IllegalArgumentException {
setValue(value); // throws if out of range
}
...
}
quindi non ci sono molti vantaggi a questo.
Ora, ci sono ancora casi in cui si potrebbe voler assegnare direttamente i valori. Per uno, forse non hai setter disponibili (anche se direi che la creazione di setter privati o di pacchetti privati è ancora auspicabile, per le ragioni sopra menzionate, per il supporto di reflection/bean, se necessario, e per la facilità di validazione in codice più complesso).
Un altro motivo potrebbe essere che forse si dispone di un costruttore che sa, in qualche modo, in anticipo che verranno assegnati valori validi, e quindi non ha bisogno di convalida e può assegnare direttamente le variabili. Questo di solito non è un motivo valido per saltare l'utilizzo di setter però.
Tuttavia, tutto sommato, è generalmente una buona idea utilizzare i setter ovunque possibile, di solito porterà a un codice più pulito e più chiaro che è più facile da mantenere man mano che aumenta la complessità.
La maggior parte degli esempi che vedete dove le persone impostano le variabili direttamente sono solo persone "pigre", il che è perfettamente accettabile se la situazione lo richiede (forse state scrivendo un programma di test o un'applicazione veloce e non volete implementare un gruppo di setter, ad esempio). Non c'è nulla di sbagliato in questo finché si tiene a mente il quadro generale e si è solo "pigri" quando è appropriato.
Qualcosa che vorrei aggiungere in base ad alcune delle altre risposte qui: Se si sostituisce un setter in una sottoclasse, e i dati che si impostano interrompono le invarianti che la classe base assume, quindi i setter rilevanti dovrebbero essere fatto finale o la classe base non dovrebbe fare quelle supposizioni. Se i setter prepotenti infrangono gli invarianti di classe base, allora c'è un problema più grande.
Noterai che il getter/setter è definitivo nell'esempio sopra. Questo perché la nostra regola è che "qualsiasi esempio deve avere un valore compreso tra 0 e 10". Questa regola si estende quindi alle sottoclassi. Se non avessimo questa regola e se un Esempio potesse assumere qualsiasi valore, non avremmo bisogno di un setter finale e potremmo consentire alle sottoclassi di scavalcare.
Spero che questo aiuti.
Credo che lo scopo di rendere private le variabili sia di isolarle dalla manipolazione diretta da ** altre ** classi. –
inoltre, la parola chiave 'this' non è richiesta per il getter; è usato solo quando c'è ambiguità (cioè se c'è un'altra variabile chiamata "nome" nello stesso ambito) – ataulm