Perché usare getter e setter / accessori?


1544

Qual è il vantaggio di usare getter e setter - che ottengono e impostano - invece di usare semplicemente campi pubblici per quelle variabili?

Se getter e setter stanno facendo qualcosa di più del semplice get / set, posso capirlo molto rapidamente, ma non sono chiaro al 100% su come:

public String foo;

è peggio di:

private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return foo; }

Considerando che il primo prende molto meno codice del boilerplate.


6
@Dean J: duplicati con molte altre domande: stackoverflow.com/search?q=getters+setters
Asaph

8
Naturalmente, entrambi sono ugualmente cattivi quando l'oggetto non ha bisogno di una proprietà per essere modificato. Preferirei rendere tutto privato, quindi aggiungere getter se utile e setter se necessario.
Tordek,

26
Google "accessors are evil"
OMG Ponies

34
"Gli accessi sono cattivi" se ti capita di scrivere codice funzionale o oggetti immutabili. Se ti capita di scrivere oggetti mutevoli con stato, allora sono piuttosto essenziali.
Christian Hayter,

Risposte:


982

In realtà ci sono molte buone ragioni per considerare l'uso degli accessor piuttosto che esporre direttamente i campi di una classe - oltre all'argomento dell'incapsulamento e rendendo più facili i cambiamenti futuri.

Ecco alcuni dei motivi di cui sono a conoscenza:

  • Incapsulamento del comportamento associato all'ottenimento o all'impostazione della proprietà: ciò consente di aggiungere più facilmente funzionalità aggiuntive (come la convalida) in un secondo momento.
  • Nascondere la rappresentazione interna della proprietà mentre si espone una proprietà utilizzando una rappresentazione alternativa.
  • Isolare l'interfaccia pubblica dal cambiamento - consentendo all'interfaccia pubblica di rimanere costante mentre l'implementazione cambia senza influire sui consumatori esistenti.
  • Controllo della semantica della gestione della vita e della memoria (smaltimento) della proprietà, particolarmente importante negli ambienti di memoria non gestiti (come C ++ o Objective-C).
  • Fornire un punto di intercettazione di debug per quando una proprietà cambia in fase di esecuzione - il debug quando e dove una proprietà è cambiata in un determinato valore può essere abbastanza difficile senza questo in alcune lingue.
  • Interoperabilità migliorata con le librerie progettate per operare contro getter / setter di proprietà: vengono in mente derisione, serializzazione e WPF.
  • Consentire agli eredi di modificare la semantica di come la proprietà si comporta e viene esposta sostituendo i metodi getter / setter.
  • Consentire al getter / setter di essere passato come espressioni lambda anziché come valori.
  • Getter e setter possono consentire diversi livelli di accesso, ad esempio il get potrebbe essere pubblico, ma il set potrebbe essere protetto.

60
+1. Solo per aggiungere: consentire il caricamento lento. Consentire la copia in scrittura.
NewbiZ,

6
@bjarkef: credo che i publicmetodi di accesso causino la duplicazione del codice ed espongano informazioni. Gli accessi pubblici non sono necessari per il marshalling (serializzazione). In alcune lingue (Java), per publicottenere gli accessori non è possibile modificare il tipo di ritorno senza interrompere le classi dipendenti. Inoltre, credo che siano in contrasto con i principi OO. Vedi anche: stackoverflow.com/a/1462424/59087
Dave Jarvis

15
@sbi: una cosa che viene acquistata utilizzando un setter di proprietà, anche in un framework ben progettato, è la possibilità che un oggetto ne informi un altro quando una proprietà cambia.
supercat

22
@supercat: Tuttavia, in genere non sto promuovendo dati pubblici. La notifica di altri oggetti può anche essere effettuata con metodi reali che forniscono un'astrazione significativa su un semplice contenitore di dati con (più o meno) campi di dati pubblici. Invece di plane.turnTo(dir); plane.setSpeed(spd); plane.setTargetAltitude(alt); plane.getBreaks().release();voglio dire plane.takeOff(alt). Quali campi di dati interni devono essere modificati per mettere l'aereo in takingOffmodalità non è una mia preoccupazione. E quali altri oggetti ( breaks) il metodo notifica non voglio sapere neanche.
sabato

8
@BenLee: davvero non so come altro dirlo. "Accessori" è solo un sinonimo di "getter / setter", e nei miei primi due commenti ho spiegato perché quelli sono un abuso del termine "OOP". Se hai bisogno di accedervi e manipolare direttamente lo stato, non è un oggetto nel senso OOP di quel termine.
sabato

480

Perché tra 2 settimane (mesi, anni) da quando ti rendi conto che il tuo setter deve fare di più che semplicemente impostare il valore, ti accorgerai anche che la proprietà è stata utilizzata direttamente in altre 238 classi :-)


84
Sono seduto e sto fissando un'app da 500k line dove non è mai stata necessaria. Detto questo, se fosse necessario una volta, inizierebbe a causare un incubo di manutenzione. Abbastanza buono per un segno di spunta per me.
Decano J

20
Posso solo invidiare te e la tua app :-) Detto questo, dipende anche dal tuo stack software. Delphi, ad esempio (e C # - penso?) Ti consente di definire le proprietà come cittadini di 1a classe in cui possono leggere / scrivere direttamente un campo inizialmente ma - se ne hai bisogno - farlo anche con metodi getter / setter. Molto conveniente. Java, purtroppo, non - per non parlare dello standard javabeans che ti costringe a usare anche getter / setter.
ChssPly76,

14
Sebbene questo sia davvero un buon motivo per usare gli accessor, molti ambienti di programmazione e editor offrono ora supporto per il refactoring (nell'IDE o come componenti aggiuntivi gratuiti) che riduce in qualche modo l'impatto del problema.
LBushkin,

62
sembra un'ottimizzazione pre-matura
cmcginty

41
La domanda che devi porre quando ti chiedi se implementare getter e setter è: Perché gli utenti di una classe dovrebbero accedere alle viscere della classe? Non importa se lo fanno direttamente o schermati da un sottile pseudo strato: se gli utenti devono accedere ai dettagli dell'implementazione, questo è un segno che la classe non offre abbastanza di un'astrazione. Vedi anche questo commento .
sabato

358

Un campo pubblico non è peggio di una coppia getter / setter che non fa altro che restituire il campo e assegnarlo. Innanzitutto, è chiaro che (nella maggior parte delle lingue) non esiste alcuna differenza funzionale. Qualsiasi differenza deve essere in altri fattori, come la manutenibilità o la leggibilità.

Un vantaggio spesso menzionato delle coppie getter / setter non lo è. C'è questa affermazione che puoi cambiare l'implementazione e che i tuoi clienti non devono essere ricompilati. Presumibilmente, i setter ti consentono di aggiungere funzionalità come la convalida in un secondo momento e i tuoi clienti non hanno nemmeno bisogno di saperlo. Tuttavia, l'aggiunta di convalida a un setter è una modifica delle sue condizioni preliminari, una violazione del contratto precedente , che era, semplicemente, "puoi inserire qualsiasi cosa qui e puoi ottenere la stessa cosa in seguito dal getter".

Quindi, ora che hai rotto il contratto, cambiare ogni file nella base di codice è qualcosa che dovresti voler fare, non evitare. Se lo eviti, stai assumendo che tutto il codice presupponesse che il contratto per quei metodi fosse diverso.

Se quello non avrebbe dovuto essere il contratto, allora l'interfaccia consentiva ai client di mettere l'oggetto in stati non validi. È esattamente l'opposto dell'incapsulamento Se quel campo non poteva davvero essere impostato su niente dall'inizio, perché la validazione non è stata fin dall'inizio?

Lo stesso argomento si applica ad altri presunti vantaggi di queste coppie getter / setter pass-through: se in seguito si decide di modificare il valore impostato, si infrange il contratto. Se si sovrascrive la funzionalità predefinita in una classe derivata, al di là di alcune modifiche innocue (come la registrazione o altri comportamenti non osservabili), si infrange il contratto della classe base. Questa è una violazione del Principio di sostituibilità di Liskov, che è visto come uno dei principi di OO.

Se una classe ha questi getter e setter stupidi per ogni campo, allora è una classe che non ha invarianti di sorta, nessun contratto . È davvero un design orientato agli oggetti? Se tutta la classe ha quei getter e setter, è solo un detentore di dati stupido, e i detentori di dati stupidi dovrebbero apparire come detentori di dati stupidi:

class Foo {
public:
    int DaysLeft;
    int ContestantNumber;
};

L'aggiunta di coppie getter / setter pass-through a tale classe non aggiunge alcun valore. Altre classi dovrebbero fornire operazioni significative, non solo operazioni già fornite dai campi. Ecco come puoi definire e mantenere utili invarianti.

Cliente : "Cosa posso fare con un oggetto di questa classe?"
Designer : "Puoi leggere e scrivere diverse variabili".
Cliente : "Oh ... figo, immagino?"

Ci sono ragioni per usare getter e setter, ma se tali ragioni non esistono, creare coppie getter / setter in nome di falsi dei incapsulati non è una buona cosa. I motivi validi per rendere getter o setter includono le cose spesso menzionate come potenziali modifiche che è possibile apportare in seguito, come la convalida o diverse rappresentazioni interne. O forse il valore dovrebbe essere leggibile dai clienti ma non scrivibile (ad esempio, leggere le dimensioni di un dizionario), quindi un semplice getter è una buona scelta. Ma quelle ragioni dovrebbero essere lì quando fai la scelta, e non solo come una cosa potenziale che potresti desiderare in seguito. Questa è un'istanza di YAGNI ( non ne avrai bisogno ).


13
Ottima risposta (+1). La mia unica critica è che mi ci sono volute diverse letture per capire come la "convalida" nell'ultimo paragrafo differiva dalla "convalida" nei primi pochi (che hai gettato in quest'ultimo caso ma promosso nel primo); adeguare la formulazione potrebbe essere d'aiuto in tal senso.
Corse della leggerezza in orbita,

14
Questa è una grande risposta, ma purtroppo l'era attuale ha dimenticato cos'è "nascondere le informazioni" o a cosa serve. Non hanno mai letto l'immutabilità e nella loro ricerca della più agile, non hanno mai disegnato quel diagramma di transizione di stato che definiva quali fossero gli stati legali di un oggetto e quindi cosa no.
Darrell Teague,

2
Un'osservazione chiave è che i getter sono molto più utili dei setter. Un getter può restituire un valore calcolato o un valore calcolato memorizzato nella cache. Tutto ciò che un setter può fare è un po 'di validazione e quindi cambiare il privatecampo. Se una classe non ha setter, è facile renderla immutabile.
Raedwald,

7
Ehm, immagino tu non sappia cosa sia un invariante di classe. Se si tratta di una struttura non banale, significa praticamente che ha invarianti da sostenere e che semplicemente non si può progettare senza quelli in mente. "Si è verificato un errore, un membro è stato aggiornato in modo errato." inoltre si legge praticamente come "Un aggiornamento di un membro ha violato gli invarianti di classe". Una classe ben progettata non consente al codice client di violare i suoi invarianti.
R. Martinho Fernandes,

5
+1 per "stupidi detentori di dati dovrebbe apparire come stupidi detentori di dati" Sfortunatamente, oggigiorno tutti sembrano progettare tutto intorno a stupidi detentori di dati, e molti framework lo richiedono persino ...
Joeri Hendrickx,

93

Molte persone parlano dei vantaggi di getter e setter, ma io voglio interpretare l'avvocato del diavolo. In questo momento sto eseguendo il debug di un programma molto grande in cui i programmatori hanno deciso di fare tutto getter e setter. Potrebbe sembrare carino, ma è un incubo di reverse engineering.

Supponiamo che tu stia esaminando centinaia di righe di codice e ti imbatti in questo:

person.name = "Joe";

È un pezzo di codice meravigliosamente semplicemente finché non ti rendi conto che è un setter. Ora segui quel setter e scopri che imposta anche person.firstName, person.lastName, person.isHuman, person.hasReallyCommonFirstName e chiama person.update (), che invia una query al database, ecc. Oh, questo è dove si stava verificando la perdita di memoria.

Capire a prima vista un pezzo di codice locale è una proprietà importante di buona leggibilità che tenditori e setter tendono a rompere. Questo è il motivo per cui provo a evitarli quando posso e minimizzo quello che fanno quando li uso.


8
Sì. Attualmente refactoring di una base di codice di grandi dimensioni, e questo è stato un incubo. Getter e setter fanno troppo, incluso chiamare altri getter e setter molto impegnati che finiscono per ridurre la leggibilità a nulla. La convalida è un ottimo motivo per usare gli accessor, ma usarli per fare molto di più di questo sembra rimuovere ogni potenziale beneficio.
Fadecomic,

31
Questo è un argomento contro lo zucchero sintattico, non contro i setter in generale.
Phil

6
Vero e vero ma, inoltre, indica come i singoli setter di proprietà aprano la porta a stati non validi senza alcun rimedio per garantire l'integrità di un determinato oggetto che consenta la fuoriuscita dell'astrazione.
Darrell Teague,

"È un pezzo di codice meravigliosamente semplicemente finché non ti rendi conto che è un setter" - ehi, era il post originale su Java o su C #? :)
Honza Zidek,

Sono completamente d'accordo sulla leggibilità. È totalmente esplicito ciò che sta accadendo quando person.name = "Joe";viene chiamato. Non ci sono innesti in termini di informazioni, l'evidenziazione della sintassi mostra che è un campo e il refactoring è più semplice (non è necessario refactoring di due metodi e un campo). In secondo luogo, tutti quei cicli cerebrali sprecati che pensano "getIsValid ()" o dovrebbe essere "isValid ()" ecc. Possono essere dimenticati. Non riesco a pensare a una sola volta che sono stato salvato da un bug da un getter / setter.
Sarà il

53

Ci sono molte ragioni. Il mio preferito è quando è necessario modificare il comportamento o regolare ciò che è possibile impostare su una variabile. Ad esempio, supponiamo che tu abbia un metodo setSpeed ​​(int speed). Ma vuoi che puoi impostare solo una velocità massima di 100. Faresti qualcosa del tipo:

public void setSpeed(int speed) {
  if ( speed > 100 ) {
    this.speed = 100;
  } else {
    this.speed = speed;
  }
}

Ora cosa succede se OVUNQUE nel tuo codice stavi utilizzando il campo pubblico e ti rendessi conto di aver bisogno dei requisiti di cui sopra? Divertiti a cercare ogni utilizzo del campo pubblico invece di modificare il tuo setter.

I miei 2 centesimi :)


62
Cercare ogni utilizzo del campo pubblico non dovrebbe essere così difficile. Renderlo privato e lasciare che il compilatore li trovi.
Nathan Fellman,

12
questo è vero ovviamente, ma perché renderlo più difficile di quanto fosse progettato per essere. L'approccio get / set è ancora la risposta migliore.
Hardryv,

28
@Nathan: trovare altri usi non è il problema. Cambiarli tutti è.
Graeme Perrow,

22
@GraemePerrow doverli modificare tutti è un vantaggio, non un problema :( E se avessi un codice che presupponeva che la velocità potesse essere superiore a 100 (perché, sai, prima di rompere il contratto, potrebbe!) ( while(speed < 200) { do_something(); accelerate(); })
R. Martinho Fernandes,

29
È un esempio MOLTO cattivo! Qualcuno dovrebbe chiamare: myCar.setSpeed(157);e dopo poche righe speed = myCar.getSpeed();E ora ... Ti auguro buon debug mentre provi a capire perché speed==100quando dovrebbe essere157
Piotr Aleksander Chmielowski,

53

In un puro mondo orientato agli oggetti, getter e setter è un terribile anti-schema . Leggi questo articolo: Getter / setter. Il male. Periodo . In breve, incoraggiano i programmatori a pensare agli oggetti come a strutture di dati, e questo tipo di pensiero è puro procedurale (come in COBOL o C). In un linguaggio orientato agli oggetti non ci sono strutture di dati, ma solo oggetti che espongono comportamenti (non attributi / proprietà!)

Puoi trovare ulteriori informazioni al riguardo nella Sezione 3.5 di Elegant Objects (il mio libro sulla programmazione orientata agli oggetti).


7
Getter e setter suggeriscono un modello di dominio anemico.
Raedwald,

7
Punto di vista interessante. Ma nella maggior parte dei contesti di programmazione ciò di cui abbiamo bisogno sono le strutture di dati. Prendendo l'esempio "Dog" dell'articolo collegato. Sì, non puoi cambiare il peso di un cane nel mondo reale impostando un attributo ... ma a new Dog()non è un cane. È un oggetto che contiene informazioni su un cane. E per tale utilizzo, è naturale essere in grado di correggere un peso registrato in modo errato.
Stephen C,

3
Bene, ti ho detto che i programmi più utili non hanno bisogno di modellare / simulare oggetti del mondo reale. IMO, non si tratta affatto di linguaggi di programmazione. Riguarda ciò per cui scriviamo programmi.
Stephen C,

3
Mondo reale o no, Yegor ha perfettamente ragione. Se quello che hai è veramente un "Struct" e non hai bisogno di scrivere alcun codice che lo faccia riferimento per nome, mettilo in una struttura hash o in altri dati. Se hai bisogno di scrivere codice per esso, inseriscilo come membro di una classe e inserisci il codice che manipola quella variabile nella stessa classe e ometti setter & getter. PS. anche se condivido principalmente il punto di vista di Yegor, sono arrivato a credere che i bean annotati senza codice siano strutture di dati in qualche modo utili - anche i getter sono talvolta necessari, i setter non dovrebbero mai esistere.
Bill K,

1
Mi sono lasciato trasportare: l'intera risposta, sebbene corretta e pertinente, non affronta direttamente la domanda. Forse dovrebbe dire "Sia setter / getter che variabili pubbliche sono sbagliati" ... Per essere assolutamente specifici, setter e variabili pubbliche scrivibili non dovrebbero mai essere usati mentre i getter sono praticamente uguali alle variabili finali pubbliche e occasionalmente sono un male necessario ma nessuno dei due è molto meglio dell'altro.
Bill K,

38

Un vantaggio di accessori e mutatori è che è possibile eseguire la convalida.

Ad esempio, se foofosse pubblico, potrei facilmente impostarlo su nulle quindi qualcun altro potrebbe provare a chiamare un metodo sull'oggetto. Ma non c'è più! Con un setFoometodo, ho potuto garantire che foonon fosse mai stato impostato null.

Gli accessori e i mutatori consentono anche l'incapsulamento: se non dovresti vedere il valore una volta impostato (forse è impostato nel costruttore e quindi utilizzato dai metodi, ma non dovrebbe mai essere modificato), non sarà mai visto da nessuno. Ma se puoi consentire ad altre classi di vederlo o modificarlo, puoi fornire l'accessorio e / o il mutatore corretti.


28

Dipende dalla tua lingua. Hai taggato questo "orientato agli oggetti" piuttosto che "Java", quindi vorrei sottolineare che la risposta di ChssPly76 dipende dalla lingua. In Python, ad esempio, non c'è motivo di usare getter e setter. Se è necessario modificare il comportamento, è possibile utilizzare una proprietà, che avvolge un getter e un setter attorno all'accesso agli attributi di base. Qualcosa come questo:

class Simple(object):
   def _get_value(self):
       return self._value -1

   def _set_value(self, new_value):
       self._value = new_value + 1

   def _del_value(self):
       self.old_values.append(self._value)
       del self._value

   value = property(_get_value, _set_value, _del_value)

2
Sì, l'ho detto in un commento sotto la mia risposta. Java non è l'unico linguaggio che utilizza getter / setter come stampella, proprio come Python non è l'unico linguaggio in grado di definire le proprietà. Il punto principale, tuttavia, rimane ancora - "proprietà" non è lo stesso "campo pubblico".
ChssPly76,

1
@jcd - per niente. Stai definendo la tua "interfaccia" (l'API pubblica sarebbe un termine migliore qui) esponendo i tuoi campi pubblici. Una volta fatto, non si può tornare indietro. Le proprietà NON sono campi perché forniscono un meccanismo per intercettare i tentativi di accesso ai campi (indirizzandoli ai metodi se definiti); ciò non è altro che zucchero di sintassi rispetto ai metodi getter / setter. È estremamente conveniente ma non altera il paradigma sottostante: esporre campi senza controllo sull'accesso ad essi viola il principio dell'incapsulamento.
ChssPly76,

14
@ ChssPly76 — Non sono d'accordo. Ho lo stesso controllo che se fossero proprietà, perché posso renderle proprietà ogni volta che ne ho bisogno. Non vi è alcuna differenza tra una proprietà che utilizza getter e setter di plateplate e un attributo non elaborato, ad eccezione del fatto che l'attributo non elaborato è più veloce, poiché utilizza il linguaggio sottostante anziché i metodi di chiamata. Funzionalmente, sono identici. L'unico modo in cui l'incapsulamento potrebbe essere violato è se pensi che le parentesi ( obj.set_attr('foo')) siano intrinsecamente superiori ai segni di uguale ( obj.attr = 'foo'). L'accesso pubblico è l'accesso pubblico.
jcdyer,

1
@jcdyer più controllo sì, ma non tanta leggibilità, altri spesso assumono erroneamente che obj.attr = 'foo'imposta semplicemente la variabile senza che accada altro
Timo Huovinen

9
@TimoHuovinen In che modo è diverso da un utente in Java supponendo che obj.setAttr('foo')"imposta semplicemente la variabile senza che accada nulla"? Se è un metodo pubblico, allora è un metodo pubblico. Se lo usi per ottenere qualche effetto collaterale ed è pubblico, allora faresti meglio a contare su tutto ciò che funziona come se si verificasse solo quell'effetto collaterale previsto (con tutti gli altri dettagli di implementazione e altri effetti collaterali, uso delle risorse, qualunque cosa , nascosto dalle preoccupazioni dell'utente). Questo non è assolutamente diverso con Python. La sintassi di Python per ottenere l'effetto è semplicemente più semplice.
ely,

25

Bene, voglio solo aggiungere che anche se a volte sono necessari per l'incapsulamento e la sicurezza delle variabili / oggetti, se vogliamo codificare un vero programma orientato agli oggetti, allora dobbiamo smettere di sovraccaricare gli accessori , perché a volte dipendiamo molto su di loro quando non è realmente necessario e ciò rende quasi lo stesso come se rendessimo pubbliche le variabili.


24

Grazie, questo ha chiarito davvero il mio pensiero. Ora ecco (quasi) 10 (quasi) buoni motivi per NON usare getter e setter:

  1. Quando ti rendi conto che devi fare molto di più che impostare e ottenere il valore, puoi semplicemente rendere il campo privato, il che ti dirà immediatamente dove hai avuto accesso direttamente.
  2. Qualsiasi convalida che esegui lì può essere solo libera dal contesto, la cui convalida raramente è in pratica.
  3. Puoi cambiare il valore impostato - questo è un incubo assoluto quando il chiamante ti passa un valore che [shock horror] vuole che tu memorizzi COSÌ COM'È.
  4. Puoi nascondere la rappresentazione interna - fantastica, quindi ti stai assicurando che tutte queste operazioni siano simmetriche, giusto?
  5. Hai isolato la tua interfaccia pubblica dalle modifiche sotto i fogli: se stavi progettando un'interfaccia e non eri sicuro che l'accesso diretto a qualcosa fosse OK, allora avresti dovuto continuare a progettare.
  6. Alcune biblioteche si aspettano questo, ma non molte: riflessione, serializzazione, oggetti finti funzionano perfettamente con i campi pubblici.
  7. Ereditando questa classe, puoi sovrascrivere la funzionalità di default - in altre parole puoi VERAMENTE confondere i chiamanti non solo nascondendo l'implementazione ma rendendola incoerente.

Gli ultimi tre che sto per lasciare (N / A o D / C) ...


11
Penso che l'argomento cruciale sia che "se stavi progettando un'interfaccia e non fossi sicuro che l'accesso diretto a qualcosa fosse OK, allora avresti dovuto continuare a progettare". Questo è il problema più importante con getter / setter: riducono una classe a un semplice contenitore di (più o meno) campi pubblici. In OOP reale , tuttavia, un oggetto è più di un contenitore di campi dati. Incapsula stato e algoritmi per manipolare quello stato. Ciò che è cruciale in questa affermazione è che lo stato dovrebbe essere incapsulato e manipolato solo dagli algoritmi forniti dall'oggetto.
sabato

22

So che è un po 'tardi, ma penso che ci siano alcune persone interessate alla performance.

Ho fatto un piccolo test delle prestazioni. Ho scritto una classe "NumberHolder" che, bene, contiene un numero intero. Puoi leggere quel numero intero usando il metodo getter anInstance.getNumber()o accedendo direttamente al numero usando anInstance.number. Il mio programma legge il numero 1.000.000.000 di volte, in entrambi i modi. Tale processo viene ripetuto cinque volte e il tempo viene stampato. Ho il seguente risultato:

Time 1: 953ms, Time 2: 741ms
Time 1: 655ms, Time 2: 743ms
Time 1: 656ms, Time 2: 634ms
Time 1: 637ms, Time 2: 629ms
Time 1: 633ms, Time 2: 625ms

(Il tempo 1 è il modo diretto, il tempo 2 è il getter)

Vedi, il getter è (quasi) sempre un po 'più veloce. Quindi ho provato con diversi numeri di cicli. Invece di 1 milione, ho usato 10 milioni e 0,1 milioni. I risultati:

10 milioni di cicli:

Time 1: 6382ms, Time 2: 6351ms
Time 1: 6363ms, Time 2: 6351ms
Time 1: 6350ms, Time 2: 6363ms
Time 1: 6353ms, Time 2: 6357ms
Time 1: 6348ms, Time 2: 6354ms

Con 10 milioni di cicli, i tempi sono quasi gli stessi. Ecco 100 mila (0,1 milioni) di cicli:

Time 1: 77ms, Time 2: 73ms
Time 1: 94ms, Time 2: 65ms
Time 1: 67ms, Time 2: 63ms
Time 1: 65ms, Time 2: 65ms
Time 1: 66ms, Time 2: 63ms

Anche con diverse quantità di cicli, il getter è un po 'più veloce del normale. Spero che questo ti abbia aiutato.


3
C'è un sovraccarico "evidente" che ha una chiamata di funzione per accedere alla memoria invece di caricare semplicemente l'indirizzo di un oggetto e aggiungere un offset per accedere ai membri. È comunque probabile che la VM abbia ottimizzato in modo piatto il tuo getter. Indipendentemente da ciò, il suddetto sovraccarico non vale la pena perdere tutti i vantaggi di getter / setter.
Alex,

16

Non utilizzare setter Getter se non necessario per la consegna corrente. Vale a dire non pensare troppo a ciò che potrebbe accadere in futuro, se qualcosa da cambiare è una richiesta di modifica nella maggior parte delle applicazioni di produzione, sistemi.

Pensa semplice, facile, aggiungi complessità quando necessario.

Non approfitterei dell'ignoranza dei proprietari di attività di profondo know-how tecnico solo perché penso che sia corretto o mi piace l'approccio.

Ho un sistema enorme scritto senza setter di getter solo con modificatori di accesso e alcuni metodi per convalidare n eseguire la logica biz. Se hai assolutamente bisogno di. Usa qualsiasi cosa.


16

Usiamo getter e setter:

  • per riusabilità
  • eseguire la convalida nelle fasi successive della programmazione

I metodi getter e setter sono interfacce pubbliche per accedere ai membri della classe privata.


Mantra dell'incapsulamento

Il mantra dell'incapsulamento è rendere i campi privati ​​e metodi pubblici.

Metodi Getter: possiamo ottenere l'accesso a variabili private.

Metodi setter: possiamo modificare campi privati.

Anche se i metodi getter e setter non aggiungono nuove funzionalità, possiamo cambiare idea tornando più tardi per rendere quel metodo

  • meglio;
  • più sicuro; e
  • Più veloce.

Ovunque è possibile utilizzare un valore, è possibile aggiungere un metodo che restituisce quel valore. Invece di:

int x = 1000 - 500

uso

int x = 1000 - class_name.getValue();

In parole povere

Rappresentazione della classe "Persona"

Supponiamo di dover memorizzare i dettagli di questo Person. Questo Personha i campi name, agee sex. In questo modo si comporta la creazione di metodi per name, agee sex. Ora, se abbiamo bisogno di creare un'altra persona, diventa necessario creare i metodi per name,age , sextutto da capo.

Invece di farlo, possiamo creare un bean class(Person)con metodi getter e setter. Quindi domani possiamo semplicemente creare oggetti di questo fagiolo class(Person class)ogni volta che dobbiamo aggiungere una nuova persona (vedere la figura). Quindi stiamo riutilizzando i campi e i metodi della classe bean, che è molto meglio.


15

Ho trascorso parecchio tempo a pensarci su per il caso Java e credo che le vere ragioni siano:

  1. Codice per l'interfaccia, non per l'implementazione
  2. Le interfacce specificano solo metodi, non campi

In altre parole, l'unico modo per specificare un campo in un'interfaccia è fornire un metodo per scrivere un nuovo valore e un metodo per leggere il valore corrente.

Quei metodi sono il famigerato getter e setter ....


1
Ok, seconda domanda; nel caso in cui si tratti di un progetto in cui non esporti la fonte a nessuno e hai il pieno controllo della fonte ... stai guadagnando qualcosa con getter e setter?
Decano J

2
In qualsiasi progetto Java non banale devi codificare le interfacce per rendere le cose gestibili e testabili (pensa a modelli e oggetti proxy). Se usi interfacce hai bisogno di getter e setter.
Thorbjørn Ravn Andersen,

15

Può essere utile per il caricamento lento. Supponi che l'oggetto in questione sia archiviato in un database e non vuoi andare a prenderlo se non ne hai bisogno. Se l'oggetto viene recuperato da un getter, l'oggetto interno può essere nullo fino a quando qualcuno non lo richiede, quindi puoi andare a prenderlo alla prima chiamata al getter.

Ho avuto una classe di pagine di base in un progetto che mi è stato consegnato che stava caricando alcuni dati da un paio di chiamate al servizio Web diverse, ma i dati in quelle chiamate al servizio Web non erano sempre utilizzati in tutte le pagine figlio. I servizi Web, per tutti i vantaggi, introducono nuove definizioni di "lento", quindi non si desidera effettuare una chiamata al servizio Web se non è necessario.

Sono passato dai campi pubblici ai getter e ora i getter controllano la cache e, se non è presente, chiama il servizio web. Quindi, con un po 'di wrapping, sono state impedite molte chiamate al servizio web.

Quindi il getter mi salva dal tentativo di capire, su ogni pagina figlio, di cosa avrò bisogno. Se ne ho bisogno, chiamo il getter, e lo troverò per me se non lo ho già.

    protected YourType _yourName = null;
    public YourType YourName{
      get
      {
        if (_yourName == null)
        {
          _yourName = new YourType();
          return _yourName;
        }
      }
    }

Quindi il getter chiama il setter?
icc97,

Ho aggiunto un esempio di codice di come l'ho fatto in passato: essenzialmente, memorizzi la classe effettiva in un membro protetto, quindi restituisci quel membro protetto nell'accessorio get, inizializzandolo se non è inizializzato.
Quillbreaker,


13

Un aspetto che mi è sfuggito finora nelle risposte, la specifica di accesso:

  • per i membri hai una sola specifica di accesso sia per l'impostazione che per la ricezione
  • per setter e getter puoi perfezionarlo e definirlo separatamente

13

EDIT: ho risposto a questa domanda perché ci sono un sacco di persone che imparano a programmare chiedendo questo, e la maggior parte delle risposte sono molto tecnicamente competenti, ma non sono così facili da capire se sei un principiante. Eravamo tutti principianti, quindi ho pensato di provare la mia risposta a una risposta più amichevole per i principianti.

I due principali sono il polimorfismo e la validazione. Anche se è solo una stupida struttura di dati.

Diciamo che abbiamo questa semplice classe:

public class Bottle {
  public int amountOfWaterMl;
  public int capacityMl;
}

Una classe molto semplice che contiene la quantità di liquido contenuta e la sua capacità (in millilitri).

Cosa succede quando lo faccio:

Bottle bot = new Bottle();
bot.amountOfWaterMl = 1500;
bot.capacityMl = 1000;

Bene, non ti aspetteresti che funzioni, giusto? Volete che ci sia una specie di controllo di sanità mentale. E peggio ancora, se non avessi mai specificato la capacità massima? Oh caro, abbiamo un problema.

Ma c'è anche un altro problema. E se le bottiglie fossero solo un tipo di contenitore? E se avessimo diversi contenitori, tutti con capacità e quantità di liquido riempito? Se potessimo solo creare un'interfaccia, potremmo permettere al resto del nostro programma di accettare quell'interfaccia, e bottiglie, taniche e ogni altra cosa funzionerebbero semplicemente in modo intercambiabile. Non sarebbe meglio? Poiché le interfacce richiedono metodi, anche questa è una buona cosa.

Finiremmo con qualcosa del tipo:

public interface LiquidContainer {
  public int getAmountMl();
  public void setAmountMl(int amountMl);
  public int getCapacityMl();
}

Grande! E ora cambiamo solo Bottle in questo:

public class Bottle extends LiquidContainer {
  private int capacityMl;
  private int amountFilledMl;

  public Bottle(int capacityMl, int amountFilledMl) {
    this.capacityMl = capacityMl;
    this.amountFilledMl = amountFilledMl;
    checkNotOverFlow();
  }

  public int getAmountMl() {
    return amountFilledMl;
  }

  public void setAmountMl(int amountMl) {
     this.amountFilled = amountMl;
     checkNotOverFlow();
  }
  public int getCapacityMl() {
    return capacityMl;
  }

  private void checkNotOverFlow() {
    if(amountOfWaterMl > capacityMl) {
      throw new BottleOverflowException();
    }
}

Lascerò la definizione di BottleOverflowException come esercizio per il lettore.

Ora nota quanto è più robusto. Ora possiamo gestire qualsiasi tipo di contenitore nel nostro codice accettando LiquidContainer anziché Bottle. E come queste bottiglie gestiscono questo tipo di cose possono differire. Puoi avere bottiglie che scrivono il loro stato su disco quando cambia, o bottiglie che salvano su database SQL o GNU sa cos'altro.

E tutti questi possono avere modi diversi di gestire varie whoopsie. Il Bottle controlla solo e se trabocca genera una RuntimeException. Ma potrebbe essere la cosa sbagliata da fare. (C'è una discussione utile da fare sulla gestione degli errori, ma lo sto tenendo molto semplice qui apposta. Le persone nei commenti indicheranno probabilmente i difetti di questo approccio semplicistico.;)

E sì, sembra che passiamo da un'idea molto semplice a ottenere rapidamente risposte molto migliori.

Si noti inoltre che non è possibile modificare la capacità di una bottiglia. Ora è incastonato nella pietra. Potresti farlo con un int dichiarandolo finale. Ma se questo fosse un elenco, potresti svuotarlo, aggiungere nuove cose e così via. Non puoi limitare l'accesso a toccare le viscere.

C'è anche la terza cosa che non tutti hanno affrontato: getter e setter usano le chiamate di metodo. Ciò significa che sembrano metodi normali ovunque. Invece di avere strana sintassi specifica per DTO e roba del genere, hai la stessa cosa ovunque.


2
Grazie per la prima spiegazione decente delle interfacce che ho letto, non fa riferimento a "telecomandi" o "macchine"
djvs

1
"Puoi avere flaconi che scrivono il loro stato su disco quando cambia, o flaconi che salvano su database SQL" Ho preso così tanto xD. Comunque, bella idea presentarlo!
Xerus,

10

Nei linguaggi che non supportano le "proprietà" (C ++, Java) o che richiedono la ricompilazione dei client quando si cambiano i campi in proprietà (C #), è più semplice modificare i metodi get / set. Ad esempio, l'aggiunta della logica di convalida a un metodo setFoo non richiederà la modifica dell'interfaccia pubblica di una classe.

In linguaggi che supportano proprietà "reali" (Python, Ruby, forse Smalltalk?) Non ha senso ottenere / impostare metodi.


1
Ri: C #. Se aggiungi funzionalità a un get / set non richiederebbe comunque una ricompilazione?
piroscafo25

@ steamer25: scusa, non è stato digitato correttamente. Intendevo dire che i clienti della classe dovranno essere ricompilati.
John Millikin,

5
L'aggiunta della logica di convalida a un metodo setFoo non richiederà la modifica dell'interfaccia di una classe a livello di lingua , ma cambia l'interfaccia effettiva , ovvero il contratto, perché modifica le condizioni preliminari. Perché si vorrebbe che il compilatore non lo trattasse come un cambiamento radicale quando lo è ?
R. Martinho Fernandes,

@ R.MartinhoFernandes come si risolve questo problema "rotto"? Il compilatore non può dire se si sta rompendo o meno. Questa è solo una preoccupazione quando stai scrivendo librerie per altri, ma lo stai facendo diventare zOMG universale qui essere draghi!
Phil

3
Richiedere la ricompilazione, come indicato nella risposta, è un modo in cui il compilatore può renderti consapevole di un possibile cambiamento di rottura. E quasi tutto ciò che scrivo è effettivamente "una biblioteca per gli altri", perché non lavoro da solo. Scrivo codice che ha interfacce che verranno utilizzate da altre persone nel progetto. Qual è la differenza? Diavolo, anche se sarò l'utente di quelle interfacce, perché dovrei mantenere il mio codice per abbassare gli standard di qualità? Non mi piace lavorare con interfacce problematiche, anche se sono io a scriverle.
R. Martinho Fernandes,

6

Uno dei principi di base del design OO: incapsulamento!

Ti offre molti vantaggi, uno dei quali è che puoi cambiare l'implementazione del getter / setter dietro le quinte, ma qualsiasi consumatore di quel valore continuerà a funzionare finché il tipo di dati rimane lo stesso.


23
Le offerte di getter e setter di incapsulamento sono ridicolmente sottili. Vedi qui .
sabato

Se la tua interfaccia pubblica afferma che "pippo" è di tipo "T" e può essere impostato su qualsiasi cosa, non puoi mai cambiarlo. Non puoi in seguito decidere di renderlo di tipo 'Y', né puoi imporre regole come vincoli di dimensione. Pertanto, se si dispone di un get / set pubblico che non fa nulla di molto set / get, non si guadagna nulla che un campo pubblico non offrirà e lo rende più ingombrante da usare. Se hai un vincolo, come ad esempio l'oggetto può essere impostato su null o il valore deve essere compreso in un intervallo, sì, sarebbe richiesto un metodo di impostazione pubblico, ma puoi comunque presentare un contratto dall'impostazione di questo valore che può " t change
thecoshman

Perché un contratto non può cambiare?
Phil

5
Perché le cose dovrebbero continuare a compilare se i contratti cambiano?
R. Martinho Fernandes,

5

È necessario utilizzare getter e setter quando:

  • Hai a che fare con qualcosa che è concettualmente un attributo, ma:
    • La tua lingua non ha proprietà (o qualche meccanismo simile, come le tracce variabili di Tcl), o
    • Il supporto della proprietà della tua lingua non è sufficiente per questo caso d'uso o
    • Le convenzioni idiomatiche della tua lingua (o talvolta del tuo framework) incoraggiano getter o setter per questo caso d'uso.

Quindi questa è molto raramente una domanda generale di OO; è una domanda specifica della lingua, con risposte diverse per lingue diverse (e diversi casi d'uso).


Da un punto di vista della teoria OO, getter e setter sono inutili. L'interfaccia della tua classe è ciò che fa, non quale sia il suo stato. (In caso contrario, hai scritto la classe sbagliata.) In casi molto semplici, dove ciò che una classe fa è, ad esempio, rappresentare un punto in coordinate rettangolari, * gli attributi fanno parte dell'interfaccia; Getter e setter lo appannano. Ma in casi tutt'altro che molto semplici, né gli attributi né i getter e i setter fanno parte dell'interfaccia.

Detto in altro modo: se ritieni che i consumatori della tua classe non dovrebbero nemmeno sapere di avere un spamattributo, tanto meno essere in grado di cambiarlo volenti o nolenti, quindi dare loro unset_spam metodo è l'ultima cosa che vuoi fare.

* Anche per quella semplice classe, potresti non voler necessariamente consentire l'impostazione dei valori xe y. Se questo è davvero una classe, non dovrebbe avere metodi come translate, rotatee così via? Se è solo una classe perché la tua lingua non ha record / strutture / tuple nominate, allora questa non è davvero una questione di OO ...


Ma nessuno sta mai progettando OO in generale. Stanno progettando e realizzando, in un linguaggio specifico. E in alcune lingue, getter e setter sono tutt'altro che inutili.

Se la tua lingua non ha proprietà, l'unico modo per rappresentare qualcosa che è concettualmente un attributo, ma in realtà è calcolato, o validato, ecc., È attraverso getter e setter.

Anche se la tua lingua ha proprietà, ci possono essere casi in cui sono insufficienti o inappropriati. Ad esempio, se si desidera consentire alle sottoclassi di controllare la semantica di un attributo, nelle lingue senza accesso dinamico, una sottoclasse non può sostituire una proprietà calcolata con un attributo.

Per quanto riguarda "e se volessi cambiare la mia implementazione in un secondo momento?" domanda (che viene ripetuta più volte in termini diversi sia nella domanda del PO che nella risposta accettata): se si tratta in realtà di una modifica di implementazione pura e si è iniziato con un attributo, è possibile cambiarlo in una proprietà senza influire sull'interfaccia. A meno che, ovviamente, la tua lingua non lo supporti. Quindi questo è davvero di nuovo lo stesso caso.

Inoltre, è importante seguire i modi di dire della lingua (o del framework) che stai utilizzando. Se scrivi bellissimo codice in stile Ruby in C #, qualsiasi sviluppatore C # esperto diverso da te avrà problemi a leggerlo, e questo è male. Alcune lingue hanno culture più forti attorno alle loro convenzioni rispetto ad altre. E potrebbe non essere una coincidenza che Java e Python, che si trovano alle estremità opposte dello spettro per quanto sono getter idiomatici, abbiano due delle culture più forti.

Oltre ai lettori umani, ci saranno biblioteche e strumenti che si aspettano che tu segua le convenzioni e che ti rendano la vita più dura se non lo fai. Collegare i widget di Interface Builder a tutto tranne che alle proprietà ObjC, o usare certe librerie di derisione Java senza getter, ti sta solo rendendo la vita più difficile. Se gli strumenti sono importanti per te, non combatterli.


4

Dal punto di vista del design dell'orientamento agli oggetti entrambe le alternative possono essere dannose per il mantenimento del codice indebolendo l'incapsulamento delle classi. Per una discussione puoi consultare questo eccellente articolo: http://typicalprogrammer.com/?p=23


3

I metodi getter e setter sono metodi di accesso, nel senso che sono generalmente un'interfaccia pubblica per cambiare i membri della classe privata. Utilizzare i metodi getter e setter per definire una proprietà. Accedete ai metodi getter e setter come proprietà esterne alla classe, anche se le definite all'interno della classe come metodi. Le proprietà esterne alla classe possono avere un nome diverso dal nome della proprietà nella classe.

Ci sono alcuni vantaggi nell'uso dei metodi getter e setter, come la possibilità di creare membri con funzionalità sofisticate a cui è possibile accedere come proprietà. Ti consentono inoltre di creare proprietà di sola lettura e di sola scrittura.

Anche se i metodi getter e setter sono utili, dovresti fare attenzione a non usarli eccessivamente perché, tra le altre cose, possono rendere più difficile la manutenzione del codice in determinate situazioni. Inoltre, forniscono l'accesso all'implementazione della tua classe, come i membri pubblici. La pratica OOP scoraggia l'accesso diretto alle proprietà all'interno di una classe.

Quando si scrivono le classi, si è sempre incoraggiati a rendere private quante più variabili possibili delle proprie istanze e aggiungere i metodi getter e setter di conseguenza. Questo perché ci sono diverse volte in cui potresti non voler permettere agli utenti di cambiare determinate variabili all'interno delle tue classi. Ad esempio, se si dispone di un metodo statico privato che tiene traccia del numero di istanze create per una classe specifica, non si desidera che un utente modifichi tale contatore utilizzando il codice. Solo l'istruzione del costruttore dovrebbe incrementare quella variabile ogni volta che viene chiamata. In questa situazione, è possibile creare una variabile di istanza privata e consentire un metodo getter solo per la variabile contatore, il che significa che gli utenti sono in grado di recuperare il valore corrente solo utilizzando il metodo getter e non saranno in grado di impostare nuovi valori usando il metodo setter.


3

Il codice si evolve . privateè ottimo per quando è necessaria la protezione dei membri dei dati . Alla fine tutte le classi dovrebbero essere una sorta di "miniprogrammi" che hanno un'interfaccia ben definita che non si può semplicemente rovinare con gli interni di .

Detto questo, lo sviluppo del software non consiste nell'impostare quella versione finale della classe come se al primo tentativo stessi premendo una statua di ghisa. Mentre ci lavori, il codice è più simile all'argilla. Si evolve man mano che lo sviluppi e scopri di più sul dominio del problema che stai risolvendo. Durante le lezioni di sviluppo possono interagire tra loro quanto dovrebbero (dipendenza che prevedi di scomporre), unire o dividere. Quindi penso che il dibattito si riduca a persone che non vogliono scrivere religiosamente

int getVar() const { return var ; }

Quindi hai:

doSomething( obj->getVar() ) ;

Invece di

doSomething( obj->var ) ;

Non solo è getVar()visivamente rumoroso, ma dà questa illusione che gettingVar()è in qualche modo un processo più complesso di quanto non sia in realtà. Il modo in cui tu (come scrittore di classe) consideri la santità varparticolarmente confuso per un utente della tua classe se ha un setter passthru - allora sembra che tu stia aprendo queste porte per "proteggere" qualcosa che insisti sia prezioso, (la santità di var), ma anche tu concedi varla protezione non vale molto per la capacità di chiunque di entrare eset var per qualunque valore vogliano, senza che tu nemmeno sbirciate da quello che stanno facendo.

Quindi programma come segue (assumendo un approccio di tipo "agile" - cioè quando scrivo codice non sapendo esattamente cosa farà / non ho tempo o esperienza per pianificare un elaborato set di interfacce in stile cascata):

1) Inizia con tutti i membri pubblici per gli oggetti di base con dati e comportamento. Questo è il motivo per cui in tutto il mio codice "esempio" in C ++ mi noterai che uso structinvece che classovunque.

2) Quando il comportamento interno di un oggetto per un membro di dati diventa abbastanza complesso (ad esempio, gli piace mantenere un interno std::listin un qualche tipo di ordine), vengono scritte le funzioni del tipo di accessorio. Perché sto programmando da solo, non sempre impostare il membro privatesubito, ma da qualche parte lungo l'evoluzione della classe del membro sarà "promosso" a uno protectedoprivate .

3) Le classi che sono completamente specificati ulteriormente e avere regole rigide sulla loro struttura interna (cioè che sanno esattamente quello che stanno facendo, e non si è a "fuck" (termine tecnico) con i suoi interni) viene data la classdesignazione, di default soci privati, e solo pochi membri selezionati possono essere public.

Trovo che questo approccio mi permetta di evitare di sedermi lì e scrivere religiosamente getter / setter quando molti membri dei dati vengono migrati, spostati, ecc. Durante le prime fasi dell'evoluzione di una classe.


1
"... un'interfaccia ben definita che non puoi semplicemente rovinare con gli interni di" e validazione nei setter.
Agi Hammerthief,

3

Vi è una buona ragione per considerare l'utilizzo di accessor se non esiste eredità di proprietà. Vedi il prossimo esempio:

public class TestPropertyOverride {
    public static class A {
        public int i = 0;

        public void add() {
            i++;
        }

        public int getI() {
            return i;
        }
    }

    public static class B extends A {
        public int i = 2;

        @Override
        public void add() {
            i = i + 2;
        }

        @Override
        public int getI() {
            return i;
        }
    }

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.i);
        a.add();
        System.out.println(a.i);
        System.out.println(a.getI());
    }
}

Produzione:

0
0
4

3

Getter e setter vengono utilizzati per implementare due degli aspetti fondamentali della programmazione orientata agli oggetti che sono:

  1. Astrazione
  2. incapsulamento

Supponiamo di avere una classe Employee:

package com.highmark.productConfig.types;

public class Employee {

    private String firstName;
    private String middleName;
    private String lastName;

    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getMiddleName() {
        return middleName;
    }
    public void setMiddleName(String middleName) {
         this.middleName = middleName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFullName(){
        return this.getFirstName() + this.getMiddleName() +  this.getLastName();
    }
 }

Qui i dettagli di implementazione di Nome completo sono nascosti all'utente e non sono accessibili direttamente all'utente, a differenza di un attributo pubblico.


1
Per me avere tonnellate di getter e setter che non fanno nulla di unico è inutile. getFullName è un'eccezione perché fa qualcos'altro. Avere solo le tre variabili pubbliche e quindi mantenere getFullName renderà il programma più facile da leggere ma avrà comunque nascosto quel nome completo. In generale sto completamente bene con getter e setter se a. fanno qualcosa di unico e / o b. ne hai solo una, sì, potresti avere una finale pubblica e tutto il resto, ma nah
FacelessTiger,

1
Il vantaggio è che puoi cambiare gli interni della classe, senza cambiare l'interfaccia. Ad esempio, invece di tre proprietà, ne avevi una: una serie di stringhe. Se hai utilizzato getter e setter, puoi apportare tale modifica e quindi aggiornare il getter / setter per sapere che i nomi [0] è il nome, i nomi [1] è in mezzo, ecc. Ma se hai appena usato proprietà pubbliche , dovresti anche modificare ogni classe a cui accede il dipendente, poiché la proprietà firstName che stanno utilizzando non esiste più.
Andrew Hows, l'

1
@AndrewHow da quello che ho visto nella vita reale, quando le persone cambiano gli interni della classe cambiano anche l'interfaccia e fanno un grande refactoring di tutto il codice
Eildosa

2

Un altro uso (in linguaggi che supportano le proprietà) è che setter e getter possono implicare che un'operazione non è banale. In genere, si desidera evitare di fare qualsiasi cosa computazionalmente costosa in una proprietà.


Non mi sarei mai aspettato che un getter o setter fosse un'operazione costosa. In questi casi è meglio utilizzare una fabbrica: utilizzare tutti i setter necessari e quindi invocare il metodo executeo il costoso build.
Hubert Grzeskowiak,

2

Un vantaggio relativamente moderno di getter / setter è che è più facile sfogliare il codice negli editor di codici con tag (indicizzati). Ad esempio, se si desidera vedere chi imposta un membro, è possibile aprire la gerarchia di chiamata del setter.

D'altra parte, se il membro è pubblico, gli strumenti non consentono di filtrare l'accesso in lettura / scrittura al membro. Quindi devi arrancare attraverso tutti gli usi del membro.


puoi fare clic destro> trova l'utilizzo su un membro esattamente come su un getter / setter
Eildosa

2

In un linguaggio orientato agli oggetti i metodi e i loro modificatori di accesso dichiarano l'interfaccia per quell'oggetto. Tra i metodi di costruzione e accessor e mutatore è possibile per lo sviluppatore controllare l'accesso allo stato interno di un oggetto. Se le variabili sono semplicemente dichiarate pubbliche, non c'è modo di regolare tale accesso. E quando stiamo usando setter possiamo limitare l'utente per l'input di cui abbiamo bisogno. Significa che il feed per quella variabile passerà attraverso un canale appropriato e il canale è predefinito da noi. Quindi è più sicuro usare setter.


1

Inoltre, questo è "a prova di futuro" la tua classe. In particolare, passare da un campo a una proprietà è un'interruzione ABI, quindi se successivamente decidi che hai bisogno di più logica di un semplice "set / get the field", allora devi interrompere ABI, che ovviamente crea problemi per qualsiasi cosa altro già compilato contro la tua classe.


2
Suppongo che cambiare il comportamento del getter o setter non sia un cambiamento di rottura allora. </sarcasm>
R. Martinho Fernandes il

@ R.MartinhoFernandes non deve sempre essere. TBYS
Phil

1

Vorrei solo lanciare l'idea dell'annotazione: @getter e @setter. Con @getter, dovresti essere in grado di obj = class.field ma non class.field = obj. Con @setter, viceversa. Con @getter e @setter dovresti essere in grado di fare entrambe le cose. Ciò preserverebbe l'incapsulamento e ridurrebbe i tempi non chiamando metodi banali in fase di esecuzione.


1
Sarebbe implementato in fase di esecuzione con "metodi banali". In realtà, probabilmente non banale.
Phil

Oggi questo può essere fatto con un preprocessore di annotazioni.
Thorbjørn Ravn Andersen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.