2013-08-03 10 views
6

La pratica di progettazione comune è rendere private le variabili di istanza e consentire a getter e setter pubblici di accedervi. Ma molte volte ho visto esempi di codice su Internet che hanno costruttori che assegnano valori direttamente alla variabile d'istanza privata invece di usare i setter all'interno dei costruttori. Mi sto perdendo qualcosa?Impostazione Java di campi privati ​​all'interno dei costruttori

public class Person{ 
    private String name; 

    public Person(String name){ 
     //is this right, seems like the whole encapsulation purpose is defeated 
     this.name = name; 

     //shouldn't this be used 
     setName(name); 
    } 

    public String getName(){ 
     return this.name; 
    } 

    public void setName(String name){ 
     this.name = name; 
    } 
} 
+7

Credo che lo scopo di rendere private le variabili sia di isolarle dalla manipolazione diretta da ** altre ** classi. –

+2

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

risposta

5

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.

+0

Aggiunto commento alla fine su setter sovrascritti. –

0

Impostare le variabili su privato è incoraggiare l'incapsulamento da altre classi.

A meno che lo setName(String) non fosse lo scopo di fare qualcosa in più (che il nome del metodo non implica), non è necessario utilizzare il setter mentre si è nella classe in cui si trova la variabile privata.

+1

Questo non è * interamente * vero, in quanto è possibile incapsulare tutta la logica di validazione in un setter e quindi avere servizi di validazione da altrove in la tua classe. –

+0

+1 sicuro, d'accordo. – ataulm

0

Questo non sconfiggere l'incapsulamento dal momento che il membro privato è ancora nascosto dalle altre classi

Se il metodo modificatore non contiene alcuna logica e solo imposta il membro allora non c'è alcuna differenza tra l'impostazione direttamente il membro di chiamare il suo metodo di setter, anche se per una migliore pratica dovrebbe essere chiamato il setter.

Il setter indica che il nome di questa persona potrebbe cambiare in futuro e lo consente facilmente senza creare nuovamente un intero oggetto persona.

2

A volte quando vuoi rendere la classe immutabile, è solo una delle cose che devi fare. E non avere metodi di setter in quel caso.

+0

C'è un argomento, principalmente per quanto riguarda la convalida, per avere invece setter privati. Ma questo è molto vero, a volte vuoi semplicemente mettere insieme un codice semplice in fretta, ed è scomodo creare dei setter privati ​​con pochissimi benefici. –

0

le variabili private sono accessibili direttamente ovunque nella classe

settng variabels privato è quello di incapsulare loro di altre classi

2

a seconda del contesto, l'uso di getter e setter è in realtà una violazione più grande di incapsulamento rispetto all'utilizzo di variabili membro nei costruttori. Se si desidera impostare il 'nome' della variabile membro di questa classe, uno di questi approcci funzionerebbe poiché la costruzione è nascosta dal chiamante e quindi non violando l'incapsulamento. Un avvertimento è che l'uso di setName all'interno del costruttore potrebbe chiamare un metodo sovrascritto in una sottoclasse che potrebbe non essere ciò che si desidera (poiché potrebbe lasciare un nome non definito nella superclasse).

Ecco una domanda simile al tuo che può fornire ulteriori indizi:

calling setters from a constructor

0

variabili inizializzazione all'interno costruttore è una pratica molto comune. Può essere usato per assegnare valori alle variabili in base a quale utente del costruttore ha chiamato. Non è possibile scrivere codice basato sul presupposto che il codice client invocherà il metodo setter per assegnare il valore alle variabili di istanza. È sempre sicuro assegnare un valore predefinito a una variabile quando viene creato il suo oggetto (cioè all'interno del costruttore).

C'è una differenza tra l'inizializzazione delle variabili all'interno del costruttore e l'impostazione su un valore diverso come da requisiti del codice chiamante (utilizzando il metodo setter). Entrambi hanno scopi e obiettivi diversi.

+0

Non penso che questo risponda alla domanda (** o forse ho frainteso **). L'OP non sta chiedendo se sia corretto inizializzare le variabili nel costruttore quando hai già fornito setter; piuttosto, OP sta chiedendo il _use_ di detti setter dall'interno del costruttore. – ataulm

0

Questo è perfettamente normale. Alcune variabili potrebbero dover essere inizializzate non appena viene creato l'oggetto, quindi ha senso passarle nel costruttore e molte volte potremmo non voler fornire setter per quelle variabili per evitare di modificare i valori dopo la creazione dell'oggetto.

+0

C'è un argomento, principalmente per quanto riguarda la convalida (specialmente per le variabili che possono essere impostate in più punti), per avere invece i setter privati. Ma questo è molto vero, a volte vuoi semplicemente mettere insieme un codice semplice in fretta, ed è scomodo creare dei setter privati ​​con pochissimi benefici. –

0

Va bene per assegnare direttamente i valori con setter fornito in classe non esegue altre elaborazioni.

incastonatori Fondamentalmente/getter sono utilizzati per fornire l'accesso a dati restrittivo private come rinvio copia dei dati invece di riferimento dell'oggetto privato, convalida dei dati in getter ecc ..

Poiché il costruttore è parte dell'oggetto stesso, e siamo sicuri che quello che stiamo facendo è giusto, quindi è ok.

+0

Vale la pena sottolineare che la frase chiave qui è "e siamo sicuri che quello che stiamo facendo è giusto". Se imponi mai delle regole sui valori dei tuoi campi, non dimenticare di accertarti che il costruttore non violi tali regole. –

Problemi correlati