Qual è il punto di proprietà?


11

Ecco alcuni argomenti per le proprietà e i miei argomenti contrari:

Più facile da usare rispetto alla scrittura di metodi getter e setter

Le coppie di metodi getter e setter sono un odore di codice. Rendere più semplice la scrittura di questi è come rendere più semplice il fallimento di un test di matematica utilizzando un modulo Scantron e compilando tutte le "C". Gli oggetti che contengono solo stato, per persistenza, non dovrebbero usare getter / setter e dovrebbero creare oggetti immutabili al momento della persistenza.

Ciò che è importante per un consumatore di un oggetto è ciò che fa, non come lo fa. Il suo comportamento è quello che fa; il suo stato è come lo fa. Se ti trovi a preoccuparti dello stato di un oggetto (tranne che per la persistenza, anche se questo rompe anche OO), semplicemente non stai facendo OOP e perdendo i suoi vantaggi.

Forniscono un'indicazione approssimativa delle prestazioni ai consumatori

Questo è qualcosa che potrebbe cambiare in futuro, per una determinata proprietà. Supponiamo che nella versione 1.0, l'accesso a PropertyX restituisca semplicemente un campo. Nella versione 1.5, se il campo è null, PropertyX utilizza il modello Null Object per creare un nuovo oggetto null. Nella versione 2.0, il campo viene ulteriormente convalidato dal metodo getter in PropertyX.

Man mano che la proprietà diventa sempre più complessa, l'indicazione delle prestazioni dell'uso di una proprietà sembra sempre meno veritiera.

Sono meglio dei campi pubblici

Questo è vero. Ma anche i metodi.

Rappresentano un aspetto fondamentalmente diverso di un oggetto rispetto a un metodo, e tutti i consumatori dell'oggetto dovrebbero preoccuparsene

Sei sicuro che entrambe le affermazioni sopra riportate siano vere?

Sono più facili da scrivere, amico

Certo, la digitazione myObject.Lengthè più semplice della digitazione myObject.Length(), ma non potrebbe essere risolta con un po 'di zucchero sintattico?


Perché usare metodi invece di proprietà?

  • Nessuna garanzia di prestazione. L'API rimarrà veritiera anche se il metodo diventa più complesso. Il consumatore dovrà profilare il proprio codice se sta eseguendo problemi di prestazioni e non fare affidamento sul word-of-API.

  • Meno per il consumatore a cui pensare. Questa proprietà ha un setter? Un metodo sicuramente no.

  • Il consumatore sta pensando da una corretta mentalità OOP. Come consumatore di un'API, sono interessato a interagire con il comportamento di un oggetto. Quando vedo le proprietà nell'API, assomiglia molto allo stato. In effetti, se le proprietà fanno troppo, non dovrebbero nemmeno essere proprietà, quindi in realtà le proprietà in uno stato ARE API sono come appaiono ai consumatori.

  • Il programmatore dell'API rifletterà più approfonditamente sui metodi con valori di ritorno ed eviterà di modificare lo stato dell'oggetto in tali metodi, se possibile. La separazione dei comandi dalle query dovrebbe essere forzata laddove possibile.


Quindi ti chiedo, perché usare le proprietà invece dei metodi? La maggior parte dei punti su MSDN sono odori di codice in sé e per sé e non appartengono a proprietà o metodi.

(Questi pensieri mi sono venuti in mente dopo aver pensato al CQS.)


5
+1. Le proprietà sono metodi con la sintassi dei campi e questo non ha senso.
Nemanja Trifunovic,

23
@Nemanja Trifunovic: ha perfettamente senso se hai scritto type GetFoo() void SetFoo()diecimila volte. In tutto il mio tempo a scrivere codice C # non sono mai stato confuso da una proprietà.
Ed S.

23
Mi sembra che tu abbia già deciso. Quale è la domanda?
Dean Harding,

9
@Nemanja Trifunovic: " Getter e setter sono generalmente cattivi" Puoi ripeterlo tutte le volte che vuoi, ma non lo renderà vero. Che ne dici di spiegare perché pensi che siano cattivi? Per quanto riguarda gli arresti anomali del SO dovuti alla digitazione del nome della proprietà anziché del nome della variabile sottostante, è impossibile perdere l'errore considerando che si bloccherà il programma non appena si chiama la proprietà ed è piuttosto raro. Quando succede, so esattamente cosa ho fatto per causarlo e l'ho risolto in due secondi. Non vedo il problema.
Ed S.

3
Solo di passaggio per sottolineare a @NemanjaTrifunovic che il motivo per cui i metodi getter e setter sono articoli malvagi è piuttosto vecchio , riguarda java e sottolinea una debolezza java : la debolezza del non avere proprietà . (quindi mostrando troppi dettagli di implementazione) ... mordendoci la coda qui. (dovrebbe essere intitolato getter e setter sono cattivi in ​​Java, perché non abbiamo dannatamente ben pensato standard su quelli )
ZJR

Risposte:


44

Perché è "metodi contro proprietà"? Un metodo fa qualcosa. Una proprietà è, beh, un membro di un oggetto. Sono cose totalmente diverse, sebbene due tipi di metodi comunemente scritti - getter e setter - corrispondano alle proprietà. Dal momento che il confronto delle proprietà con i metodi in generale non è significativo, supporrò che intendevi parlare di getter / setter.

Le coppie di metodi getter e setter sono un odore di codice.

Non necessariamente, direi, ma in entrambi i casi questo non è una questione di getter / setter rispetto a proprietà, ma una questione di utilizzo di entrambi. Si noti inoltre che è possibile, ad esempio, escludere la setXparte proprio come è possibile creare proprietà di sola lettura.

Ciò che è importante per un consumatore di un oggetto è ciò che fa, non come lo fa. Il suo comportamento è quello che fa; il suo stato è come lo fa. Se ti trovi a preoccuparti dello stato di un oggetto (tranne che per la persistenza, anche se questo rompe anche OO), semplicemente non stai facendo OOP e perdendo i suoi vantaggi.

Un atteggiamento altamente discutibile. Se la GUI vuole generare dati conservati da a DataStuffManagerImpl, deve in qualche modo ricavarne quel numero (e no, non è possibile aggiungere metà dell'applicazione alla classe di widget).

Man mano che la proprietà diventa sempre più complessa, l'indicazione delle prestazioni dell'uso di una proprietà sembra sempre meno veritiera.

[I metodi hanno] Nessuna garanzia di prestazione. L'API rimarrà veritiera anche se il metodo diventa più complesso. Il consumatore dovrà profilare il proprio codice se sta eseguendo problemi di prestazioni e non fare affidamento sul word-of-API.

In quasi tutti i casi, tutta la logica di convalida ecc. È ancora efficacemente O (1), o comunque trascurabile nei costi. Altrimenti, forse sei andato troppo lontano ed è tempo di cambiare. E un getX()metodo è di solito trattato anche a buon mercato!

Certo, digitando myObject.Length è più facile che digitare myObject.Length (), ma non è possibile risolverlo con un po 'di zucchero sintattico?

Le proprietà sono lo zucchero sintattico.

Meno per il consumatore a cui pensare. Questa proprietà ha un setter? Un metodo sicuramente no.

"C'è un setter per questo getter?" Stessa differenza.

Il programmatore dell'API rifletterà più approfonditamente sui metodi con valori di ritorno ed eviterà di modificare lo stato dell'oggetto in tali metodi, se possibile. La separazione dei comandi dalle query dovrebbe essere forzata laddove possibile.

Non sono sicuro di cosa stai cercando di dirci qui. Per le proprietà, esiste una legge non scritta ancora più forte per non causare effetti collaterali.


3
+1, E non è una legge non scritta. Le linee guida sull'utilizzo delle proprietà su MSDN sono state scritte con molti altri. Penso che l'OP dovrebbe affrontarli per chiarire molti dubbi. E non posso pubblicare un link qui poiché sto scrivendo questo dal mio telefono, ma le linee guida dovrebbero essere facili da trovare.
deciclone


@delnan: le proprietà non sono lo zucchero sintattico. Le proprietà possono essere trattate come campi (possono essere usate come target di assegnazione, se hanno un setter). I metodi non possono.
xofz,

1
@SamPearson: obj.x = ymappe obj.setX(y)e obj.xmappe a obj.getX(). Com'è diverso?

1
@SamPearson è possibile modificare la visibilità di un setter proprietà e getter indipendentemente l'uno dall'altro. Lo uso sempre con i miei oggetti Entity Framework: i miei setter sono protetti (quindi solo il framework può impostare un valore). Quindi è perfettamente fattibile dire int length = myObject.Length senza consentire myObject.Length = 10
Michael Brown

19

Le coppie di metodi getter e setter sono un odore di codice.

Questo è un presupposto errato e completamente errato. I metodi Get / Set sono un modo per incapsulare un membro di dati e non sono in alcun modo un "odore di codice". Odio davvero il modo in cui alcune persone lanciano il termine "odore di codice", ma comunque ...

Questo è qualcosa che potrebbe cambiare in futuro, per una determinata proprietà. Supponiamo che nella versione 1.0, l'accesso a PropertyX restituisca semplicemente un campo. Nella versione 1.5, se il campo è null, PropertyX utilizza il modello Null Object per creare un nuovo oggetto null. Nella versione 2.0, il campo viene ulteriormente convalidato dal metodo getter in PropertyX.

Man mano che la proprietà diventa sempre più complessa, l'indicazione delle prestazioni dell'uso di una proprietà sembra sempre meno veritiera.

Sembra un'API mal progettata, non vedo come sia colpa della sintassi delle proprietà.

Le proprietà in C # erano semplicemente zucchero sintattico per uno schema molto comune che ha reso le nostre vite come programmatori un po 'più facili. Tuttavia, in questi giorni, se si desidera utilizzare l'associazione dei dati, è necessario "utilizzare" le proprietà, quindi ora sono un po 'più dello zucchero sintattico. Immagino di non essere assolutamente d'accordo con nessuno dei tuoi punti e non capisco perché non ti piaccia una funzionalità linguistica che supporti direttamente un modello comune.


1
Ho intenzione di dare una taglia per trovare un termine migliore di odore di codice. Basta leggere un libro sul refactoring dove viene usato circa mille volte. È come le unghie di una lavagna.
JeffO,

1
@Jeff O: Sì, trovo che le persone che sembrano buttare quel termine più tipicamente non abbiano molta esperienza.
Ed S.

6
@Jeff O e ​​@Ed S: IME, "odore di codice" è diventato il termine di riferimento che le persone usano quando intendono davvero "Non mi piace, ma in realtà non ho un motivo"
Steven Evers

3
@SnOrfus: Sì, o quando hanno opinioni "religiose" che spesso hanno poco senso in pratica, come "un metodo non dovrebbe mai avere più di un numero X di righe" , che a sua volta di solito è solo una ripetizione di qualcosa che hanno letto da qualche parte.
Ed S.

1
L' uso inappropriato dei metodi getter / setter è un odore di codice, ma lo stesso dovrebbe essere l'uso inappropriato di qualsiasi cosa . Anche quando le cose hanno casi d'uso ristretti, impiegare tali cose per quei casi d'uso non dovrebbe essere considerato un odore di codice. La creazione di setter per ogni cosa non dovrebbe essere un'abitudine cieca, ma non si dovrebbe aver paura di includerli quando appropriato. Ciò che è necessario è bilanciare l'utilità per i clienti di essere in grado di cambiare stato, anziché essere in grado di scoprire in futuro quale stato era prima (facile se lo stato è immutabile). Entrambi sono utili, ma il codice deve sceglierne uno.
supercat,

10

La tua premessa è sbagliata.

Le proprietà non sono in alcun modo un contratto per l'esecuzione o l'implementazione interna o altro.
Le proprietà sono coppie di metodi speciali, che rappresentano semanticamente un attributo, se lo desideri. E quindi l' unico contratto è che una proprietà si comporta come ci si aspetterebbe da un attributo.
Se chiedo il colore di un oggetto, non faccio ipotesi sul fatto che sia ottenuto da un semplice accesso al campo o se sia calcolato appena in tempo.
Il punto è avere la capacità di esporre il comportamento di un attributo usando i metodi, mentre è trasparente per l'utente dell'interfaccia, sia che si utilizzi un campo o gli accessori.

Avere attributi (e in realtà nasconderne l'implementazione, come le proprietà si oppongono ai campi) è una potente funzione dichiarativa , che è la base per avere ispettori di oggetti visivi e altra generazione di viste automatiche, per l'associazione di dati e molte altre cose utili. E, soprattutto, trasporta chiaramente queste informazioni anche per i tuoi colleghi programmatori.


6

Il consumatore sta pensando da una corretta mentalità OOP. Come consumatore di un'API, sono interessato a interagire con il comportamento di un oggetto. Quando vedo le proprietà nell'API, assomiglia molto allo stato. In effetti, se le proprietà fanno troppo, non dovrebbero nemmeno essere proprietà, quindi in realtà le proprietà in uno stato ARE API sono come appaiono ai consumatori.

Una proprietà dovrebbe essere uno stato. Se il setter sottostante o il codice getter cambiano per aggiungere significativamente all'elaborazione richiesta per impostare o ottenere lo stato, in realtà non è più una proprietà e dovresti sostituirlo con metodi. Dipende da te come sviluppatore del codice.

Inserire troppo codice (quanto dipende troppo) in un setter o getter è sbagliato, ma solo perché è possibile non è un motivo per buttare via lo schema in tutti i casi.


6

Una cosa che ti manca e non so se ciò sia dovuto all'ignoranza o se stai trascurando intenzionalmente questo dettaglio, è che le proprietà SONO metodi.

Quando si utilizza la sintassi delle proprietà di C #, il compilatore crea in modo silenzioso metodi getter e setter con metadati che indicano ai linguaggi che comprendono le proprietà come una caratteristica sintattica di prima classe per trattarli come tali. Questo è, in effetti, lo zucchero sintattico che stai chiedendo. Alcune lingue che possono essere eseguite sul CLR non ti nascondono completamente questo dettaglio (Boo, se la memoria mi serve e alcune implementazioni Lisp), e puoi chiamare esplicitamente i getter e i setter.

Le proprietà hanno occasionalmente effetti collaterali, come l'attivazione di eventi di notifica di modifica (INotifyPropertyChanged, ad esempio) o la marcatura di un'istanza di una classe come sporca. Questo è dove hanno il loro vero valore, sebbene crearli sia un po 'più di lavoro (tranne in Boo, che ha macro esperte di sintassi).

Ora, la domanda più ampia è se i metodi getter e setter siano, in effetti, una buona cosa. Ci sono chiaramente dei compromessi; se si dispone di metodi mutatori, il codice è intrinsecamente meno parallelizzabile, poiché ora è necessario gestire i problemi di sincronizzazione dei thread. Ed è del tutto possibile che rischierai di violare la Legge di Demetra usando metodi mutatori (che siano chiamati proprietà o metodi getter / setter; sono equivalenti), perché è così dannatamente conveniente farlo.

Ma a volte è la cosa giusta da fare. A volte il tuo problema è quello di prendere i dati da qualche fonte, cambiarli un po ', presentare i dati aggiornati all'utente e salvare le modifiche. Quel linguaggio è ben servito dalle proprietà. Come dice l' articolo di Allen Holub , solo perché getter e setter hanno problemi non significa che non dovresti mai usarli. (Pappagallo astratto Guruspeak considerato dannoso). Anche quando segui l'approccio Classe / Responsabilità / Collaboratori, finisci comunque per esporre informazioni o presentazioni di informazioni a qualcuno; il punto è minimizzare la superficie dell'entanglement.

Il lato positivo delle proprietà è che è molto facile avere un altro oggetto sfruttarle. Il rovescio della medaglia delle proprietà è che è molto facile che un altro oggetto ne approfitti e non si può facilmente prevenirlo.

La mutazione dell'oggetto ha senso a livello di controller, ad esempio in un'architettura MVC. Questo è il tuo collaboratore. Anche il tuo punto di vista è un collaboratore, ma non dovrebbe mutare direttamente i tuoi oggetti, perché ha responsabilità diverse. Il rolling del codice di presentazione negli oggetti business non è necessariamente il modo giusto per evitare getter / setter.

L'equazione cambia un po 'se si usano astrazioni funzionali, piuttosto che OO pure, il che generalmente rende banali le copie di un oggetto "record" con un paio di modifiche, anche se non libere. Ehi, se stai cercando di ottenere garanzie sulle prestazioni, le proprietà sono generalmente più prevedibili della ricostruzione pigra di una collezione immutabile.


5

Un altro motivo importante nel mio libro per l'utilizzo delle proprietà è che possono aumentare notevolmente la leggibilità.

account.setBalance(Account.getBalance()+deposit);

è chiaramente molto meno leggibile di

account.Balance += deposit;

6
Ad eccezione del fatto che il saldo non dovrebbe essere una proprietà perché è certo che deve esserci una logica aziendale significativa associata alla modifica (verifica dello scoperto, addebito del servizio di addebito; registrazione delle transazioni, ecc.) Il punto di leggibilità è completamente valido se applicato a un altro esempio ( Temperature, BackgroundColour ecc.)
Kate Gregory

9
Perché non account.Deposit (importo)?
xofz,

4
@ Sam Pearson: +1. Un esempio perfetto del motivo per cui getter / setter spesso indicano un design scadente.
Nemanja Trifunovic,

4

Hai quasi il contrario punto di vista religioso per me :)

Quando mi sono trasferito da Delfi a Java, la mancanza di proprietà è stata un grande affronto per me. Ero abituato a dichiarare una proprietà o a indicarla direttamente a una variabile privata o a scrivere un getter e setter (protetto), quindi a "installarli" sulla proprietà. Questo incapsulava la proprietà e controllava il modo in cui doveva essere accessibile in modo chiaro e inequivocabile. Potresti avere una proprietà di sola lettura che calcolava il totale quando vi si accedeva e chiamarlo "Totale" non "_getTotal ()" o discorsi simili. Significava anche che potevi limitare l'accesso alle proprietà rendendole protette nella classe base astratta e spostandole in pubblico o pubblicate in sottoclassi.

Per me, le proprietà sono un modo più naturale ed espressivo di impostare e ottenere lo stato dell'oggetto. Fare affidamento su convenzioni di codifica non forzata è più un "odore di codice" di qualsiasi cosa tu stia criticando le proprietà. Inoltre, come altri hanno già detto, trovare un uso mal progettato delle proprietà e usare i suoi fallimenti per provare a respingere il concetto di proprietà in generale è una forma estremamente negativa. È possibile che tu abbia visto solo un cattivo uso delle proprietà e supponga che sia così suppongo, ma dovresti fare ulteriori ricerche prima di diventare troppo dogmatico.


+1 Che effettivamente un uso reale di una proprietà. Bella risposta. " Significava anche che potevi limitare l'accesso alle proprietà rendendole protette nella classe base astratta e poi spostandole in pubblico o pubblicate in sottoclassi. "
Karthik Sreenivasan,

Delphi abusa di proprietà e nausea. Non si ordina l'elenco, si imposta la sua sorted proprietà su true. Quindi impostandolo su falseti dà la lista originale. : D O lo mescola casualmente? : D O qualunque cosa, è solo stupido. Inoltre, è dannatamente lento rispetto a un set ordinato corretto. Le proprietà non sono male, ma ho imparato a usarle con parsimonia (fino al punto di essere abbastanza contento di getter e setter; sto usando principalmente Java).
maaartinus,

1

Uno dei motivi per cui le proprietà sono state introdotte in Java Beans Framework è stato quello di consentire l'integrazione con un IDE: è possibile trascinare tali componenti sull'IDE e modificare le proprietà utilizzando gli editor di proprietà.

(allora erano solo getter e setter regolari - e erano definiti solo dalla convenzione di denominazione - e questo aveva davvero un odore)

Oggi ci sono ancora più casi in cui le proprietà sono accessibili e modificate non tramite un normale codice, come durante il debug.


1

Un altro punto di vista: provenivano davvero da VB. Ricorda, nei giorni bui del 20 ° secolo, quando .NET fu concepita come una grande enfasi era che si trattava di un facile rimpiazzo per VB in modo che i tuoi programmatori VB potessero semplicemente trascinare e rilasciare le cose sui moduli web. VB aveva proprietà, quindi era necessario mantenere quella funzione affinché le cose traducessero nel modo giusto.


1
Anders Heljsberg progettò C # (e alcuni degli IL) e progettò anche Delphi, che aveva proprietà.
Jesse C. Slicer,

1

Esistono almeno due scopi per le proprietà:

  • Sono concettualmente identici ai campi anche se implementati in modo diverso. Un getter non dovrebbe cambiare lo stato dell'oggetto e non dovrebbe avere effetti collaterali. Un setter dovrebbe cambiare lo stato in modo concettualmente simile alla modifica di un campo e non avere altri effetti collaterali.

  • Sono sintatticamente identici ai campi pubblici (possibilmente di sola lettura). Ciò significa che un campo pubblico può essere modificato in una proprietà senza interrompere i chiamanti a livello di origine.


Sì, ma nota la parola "dovrebbe". Non c'è nulla sulle proprietà che impediscono agli effetti collaterali di avere effetti collaterali e in effetti ho visto numerosi casi in cui era così.
Nemanja Trifunovic,

1
Cambiando un campo pubblico in una proprietà si romperà la compatibilità binaria, il codice che consuma dovrà essere ricompilato - anche se non modificato,
suppongo

@MattDavey: grazie. Questo è ciò che intendevo. Modificato.
dsimcha,
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.