Come si è evoluto OOP per includere la nozione di Proprietà


11

Sono venuto da un background C ++ e sto andando tutto fuori C # nel mio lavoro attuale e ho appena letto un sacco di domande e risposte su qual è la differenza tra campi pubblici e proprietà e tutto il avanti e indietro nelle variazioni e incarnazioni di questo domanda di base (ad esempio questo post SO e tutte le relative domande collegate ). Tutte queste domande sono affrontate in termini di differenze pratiche che danno per scontata l'esistenza di un sistema di proprietà, ma penso che sarebbe bene affrontare questo argomento in termini di ciò che i progettisti di tutte le lingue che hanno deciso di supportare le proprietà nella prima luogo stava pensando (controlla l'elenco nell'articolo di Wikipedia qui). In che modo OOP si è evoluto da C ++ / Java per estendersi in quello che l'articolo di Wikipedia identifica in modo interessante come mezzo tra metodi e dati dei membri:

"Ossia, le proprietà sono intermedie tra il codice membro (metodi) e i dati membro (variabili di istanza) della classe e le proprietà forniscono un livello di incapsulamento più elevato rispetto ai campi pubblici."

MSDN aggiunge ulteriore sfondo:

"Sebbene le proprietà siano tecnicamente molto simili ai metodi, sono abbastanza diverse in termini di scenari di utilizzo. Dovrebbero essere viste come campi intelligenti. Hanno la sintassi chiamante dei campi e la flessibilità dei metodi."

Vorrei sapere come è arrivato a che questo livello intermedio di incapsulamento si è rivelato utile per la programmazione in generale. Suppongo che questo concetto non fosse presente alla prima incarnazione dei linguaggi di programmazione che esprimeva il paradigma OOP.


8
La funzione di linguaggio nudo è solo un comodo zucchero sintattico per i metodi getter e setter. Non so se ci siano ragioni più profonde dietro l'interpretazione e la terminologia.

In una serie di esperti OO il titolo della domanda può essere provocante e può distrarre da ciò che stavi davvero chiedendo. Non che mi prenda come un esperto OO, sono solo un "utente OO" per diversi anni.
Doc Brown,

È una bontà sintattica che mi è sfuggita passare da "metodi senza parametri" in Python a C ++. BMI = bob.weight/sq(bob.height)legge meglio senza ()IMO.
OJFord,

Penso che le proprietà fossero nell'originale (non .net) Visual Basic, come un modo per configurare l'oggetto Active X (COM). La griglia delle proprietà in questo strumento probabilmente aveva a che fare con l'adozione delle proprietà nelle lingue. Si noti che Visual Basic originale non era orientato agli oggetti in molti modi, ma aveva la capacità di creare qualcosa di simile alle classi.
Frank Hileman,

Continua: la finestra delle proprietà era un modo per configurare gli oggetti senza scrivere codice. Si chiamava sviluppo RAD. Questo link contiene uno screenshot della finestra delle proprietà VB6: microsoft.com/mspress/books/WW/sampchap/4068.aspx
Frank Hileman,

Risposte:


5

Si tratta di incapsulamento e principio di accesso uniforme.

Un oggetto dovrebbe essere in grado di rispondere a un messaggio restituendo dati esistenti o eseguendo un metodo, ma il mittente non dovrebbe essere in grado di dire quale è quale. O se lo visualizzi dal lato del mittente: il mittente dovrebbe essere in grado di accedere ai dati esistenti o eseguire un metodo attraverso un'interfaccia uniforme.

Esistono diversi modi per raggiungere questo obiettivo:

  • sbarazzarsi dei dati del tutto, basta avere metodi (Newspeak fa questo)

    • una forma meno radicale di quanto sopra: sbarazzarsi dei dati nell'interfaccia pubblica , ovvero rendere i dati sempre privati, nell'interfaccia pubblica, esporre solo i metodi (Smalltalk, Ruby farlo)
  • sbarazzarsi del tutto dei metodi, avere solo i dati (Self fa questo, i "metodi" sono solo Methodoggetti assegnati alle variabili di istanza, le variabili di istanza vengono cercate con invio virtuale)

  • non fare alcuna distinzione sintattica o semantica tra metodi e dati (Scala fa questo, accedere a un campo è sintatticamente indistinguibile dal chiamare un metodo senza un elenco di argomenti ( foo.bar), assegnare a un campo è sintatticamente indistinguibile dal chiamare un metodo appositamente chiamato ( foo.bar = baz) è lo stesso come ad foo.bar_=(baz)esempio chiamando un metodo chiamato foo_=, e i valori di sola lettura possono essere sovrascritti o implementati da un metodo senza un elenco di parametri (cioè val foo) in una superclasse può essere sovrascritto (o abstract valessere implementato) in una sottoclasse con un metodo def foo)

Java, tuttavia, non segue il principio di accesso uniforme. In Java, è possibile distinguere tra l'accesso ai dati e l'esecuzione di un metodo. foo.barè diverso da foo.bar(). La ragione di ciò è che i campi e i metodi sono semanticamente e sintatticamente distinti.

C # tenta di risolvere questo problema aggiungendo proprietà al linguaggio, in sostanza metodi che sembrano campi. Tuttavia, le chiamate ai metodi continuano a sembrare diverse dagli accessi ai campi e alle proprietà. I campi e le proprietà ora hanno Accesso uniforme, ma i metodi non lo fanno ancora.

Quindi, questo in realtà non risolve il problema: non è possibile correggere due diversi modi per accedere alle cose aggiungendo un terzo modo per accedere alle cose! Anche se quel terzo modo sembra uno degli altri due modi, avrai comunque (almeno) due modi diversi. Puoi risolverlo solo eliminando tutti i diversi modi tranne uno o eliminando le differenze.

È perfettamente bene avere un linguaggio con metodi, proprietà e campi, ma tutti e tre dovrebbero avere un accesso uniforme.


1
Perché tu (e altri) pensate che mantenere l'accesso uniforme sia così importante? Con un metodo potresti voler dargli dei parametri per cambiare ciò che fa o agisce. Con un campo o una proprietà non si dispone di questa capacità, in genere si restituiscono solo i dati (sebbene una proprietà possa essere implementata come esecuzione di un metodo anziché semplicemente esporre un campo privato). Mi sembra intuitivo, forse solo perché ci sono abituato, ma cosa guadagneresti in eleganza o produttività applicando un accesso uniforme? Hai paura di perdere i dettagli dell'implementazione al di fuori della classe?
Mike supporta Monica il

1
L'UAP consiste nel riservare la libertà di modificare i dettagli dell'implementazione senza interrompere l'interfaccia pubblica. Il solito esempio è l'aggiunta della registrazione. Se offro l'accesso tramite un metodo, posso cambiare banalmente gli interni del metodo per scrivere su un registro. Con un campo pubblico, non posso aggiungere la registrazione senza prima trasformarlo in un metodo, che rompe tutto il codice client. Se non è possibile rischiare di interrompere le modifiche, è indispensabile utilizzare i metodi. Le proprietà sono il compromesso ottimale perché sono metodi completi ma sembrano campi. L'adesione all'UAP migliora l'incapsulamento e riduce l'accoppiamento stretto.
amon,

Molte buone risposte a questa domanda, ma penso che questa abbia colpito la testa tirando fuori gli aspetti più fondamentali della natura dei linguaggi di programmazione ed elaborando il relativo concetto formale di UAP. Solido
jxramos,

18

Beh, non sono sicuro al 100%, ma immagino che le cose siano probabilmente più semplici di quanto ti aspetti. Dalle scuole di modellazione OO degli anni '90, c'era una richiesta di classi di modellazione con attributi membri incapsulati e, quando implementato in linguaggi come C ++ o Java, questo in genere porta a codice con molti getter e setter, quindi un sacco di "rumore" codice per un requisito relativamente semplice. Nota che la maggior parte (probabilmente tutti, non hanno verificato questo) le lingue elencate nel tuo articolo Wikipedia collegato hanno iniziato a introdurre "proprietà" degli oggetti alla fine degli anni '90 o successivi.

Immagino che questo sia stato il motivo principale per cui i progettisti del linguaggio hanno deciso di aggiungere un po 'di zucchero sintattico per ridurre quel rumore. E sebbene le proprietà non siano sicuramente un "concetto OO di base", almeno hanno qualcosa a che fare con l'orientamento agli oggetti. Non mostrano "un'evoluzione di OOP" (come presuppone il titolo della domanda), ma supportano la modellazione OO a livello di linguaggio di programmazione per facilitare l'implementazione.


Non ha nulla a che fare con la programmazione orientata agli oggetti, tranne nel senso che una proprietà è un'astrazione di un campo e che i campi fanno parte della programmazione orientata agli oggetti. Ma le proprietà non sono necessarie per la programmazione orientata agli oggetti, come si nota correttamente.
Frank Hileman,

2
@FrankHileman: "una proprietà è un'astrazione di un campo e i campi fanno parte della programmazione orientata agli oggetti" - beh, mi sembra che tu accetti che il concetto abbia in realtà almeno qualcosa a che fare con OOP. Ed è per questo che mi hai sottovalutato?
Doc Brown,

3
lol. Puoi biasimarlo? Scivolò dal bagno e sbatté la testa sul lavandino. Comunque ... Il modo in cui l'ho sempre visto è che le proprietà non sono strettamente legate a OO. Aiutano con l'incapsulamento e l'incapsulamento aiuta con OO.
MetaFight il

1
Ha! Questa è piuttosto un'introduzione a programmers.stackexchange per me. Lol, molto più entusiasta della mia esperienza equivalente nello stackoverflow normale :-p Un buon modo per confondere la giornata!
jxramos,


11

Lo hai al contrario (tipo di). Lambda Calculus costituisce praticamente la base formale principale per i linguaggi di programmazione, ed è stata per decenni. Non ha campi.

Per modellare lo stato mutabile, è necessario effettuare due astrazioni. Uno rappresenta l'impostazione di uno stato e un altro che recupera quello stato (capitolo 13 nella mia versione di TaPL per riferimento). Suona familiare? Da un background teorico , OO non si è evoluto per avere queste cose. OO ha letto il linguaggio di programmazione 101 e ha fatto un piccolo passo avanti.

Da un punto di vista pratico , ci sono due motivazioni abbastanza chiare. Provieni da uno sfondo C ++, quindi cosa dovrebbe succedere se tu avessi un campo pubblico - diciamo ... il testo in una casella di testo. Cosa succede quando vuoi cambiare il tuo design in modo che "ogni volta che questa casella di testo cambia, blah"? Puoi uccidere quel campo, creare una funzione o due e collegare quella logica, dal momento che non puoi fidarti degli sviluppatori per chiamare loro stessi "UpdateTextbox". Questa è una modifica molto importante al tuo api (e sfortunatamente è ancora una svolta alla realizzazione delle proprietà di .NET). Questo tipo di comportamento è tutto il luogo nel API di Windows. Dato che questo è un grosso problema per Microsoft, C # probabilmente voleva renderlo meno doloroso.

L'altra grande motivazione sono i fagioli di Java e i loro parenti. Sono stati creati numerosi framework per utilizzare la riflessione Java per cercare GetXe SetXaccoppiare e trattarli efficacemente come proprietà moderne. Ma dal momento che non erano veri e propri costrutti linguistici, queste strutture erano fragili e immutabili. Se scrivessi un nome, le cose si romperanno in silenzio. Se uno è stato refactored, nulla ha spostato l'altro lato della proprietà. E fare tutto il campo / get / set boilerplate è stato prolisso e noioso (anche per Java!). Da quando C # è stato sviluppato in gran parte come "Java con lezioni apprese" quel tipo di dolore era una di quelle lezioni.

Ma la cosa più importante è che il concetto di proprietà ha avuto successo. È facile da capire, è facile da usare. Questi aiutano notevolmente l'adozione e, come strumento , i programmatori hanno scoperto che le proprietà risolvono un sottoinsieme di problemi in modo più chiaro rispetto a funzioni o campi.


7
Ti ho votato per lo più per troppi riferimenti a merde formali irrilevanti. Le implementazioni effettive dei linguaggi di programmazione hanno cose molto più serie da considerare rispetto al fatto che il loro modello sia stato incluso o meno nel calcolo lambda.
DeadMG

9
@DeadMG - questo è certamente vero, ma d'altra parte gli implementatori del linguaggio di programmazione avranno sempre familiarità con quell'irrilevante schifezza formale . Pensare che non abbia avuto un impatto sui loro progetti è ingenuo.
Telastyn,

3
Non si tratta sicuramente di "merda formale irrilevante". Tuttavia, il calcolo lambda potrebbe non essere stato considerato molto per i primi linguaggi di programmazione. In tal caso, le CPU sarebbero probabilmente più orientate verso quella mentalità.
Frank Hileman,

3
@FrankHileman - Sono abbastanza sicuro che Lisp l'abbia considerato ...
Telastyn il

4
@Telastyn - sì - e Lisp inizialmente non doveva essere un linguaggio di programmazione, ricordi?
Frank Hileman,

3

In .net in particolare, le proprietà hanno origine dai vecchi tempi di Visual Basic che, a quanto pare, non erano orientati agli oggetti nel modo in cui pensiamo oggi. Era in gran parte costruito attorno all'allora nuovo sistema COM che trattava superficialmente tutto non necessariamente come classi ma in termini di componenti che avrebbero esposto proprietà a cui era possibile accedere sia nel codice che negli editor grafici. Quando VB e il C # appena creato sono stati uniti in .net, VB ha ottenuto molte funzionalità OOP e ha mantenuto le proprietà poiché rimuoverle sarebbe come un passo indietro - immagina se lo strumento di aggiornamento automatico del codice che avevano in Visual Studio fosse stato sostituendo tutte le proprietà con getter e setter e interrompendo la compatibilità con tutte le librerie COM. Sarebbe logico supportarli in tutto.


Non credo che dovresti ignorare la discendenza di C # che proveniva da Delphi e da prima, Object Pascal e Turbo Pascal with Objects. Questi erano orientati agli oggetti e avevano proprietà (anche se non ricordo se OP avesse proprietà da TP5.5 o se fossero state aggiunte; presumibilmente furono continuate in C # da Anders perché erano pragmaticamente una buona idea.
Amaca,

Molto interessante che ti sia capitato di essere l'unico a colpire l'aspetto componente di questa domanda. Ho appena aggiunto un commento alla mia domanda collegandomi a un sito che elencava le proprietà come parte di un modello di evento metodo-proprietà che C # soddisfa. Ho quindi cercato nuovamente nella pagina della mia domanda il "componente" atterrando alcuni falsi positivi, ma la tua risposta penso in realtà si sovrappone a ciò a cui mi sono collegato.
jxramos,

3

Le proprietà non hanno nulla a che fare con la programmazione orientata agli oggetti, poiché le proprietà sono solo zucchero sintattico. Le proprietà sembrano superficialmente campi e, nel mondo .net, si raccomanda che si comportino come campi in qualche modo, ma non sono campi in alcun senso. Le proprietà sono zucchero sintattico per uno o due metodi: uno per ottenere un valore e uno per impostare un valore. Il metodo set o get può essere omesso, ma non entrambi. Potrebbe non esserci campo che memorizzi il valore restituito dal metodo get. Poiché condividono una sintassi con i campi e poiché usano spesso i campi, le persone associano le proprietà ai campi.

Le proprietà presentano vantaggi rispetto ai campi:

  • In un metodo di set di proprietà, prima di archiviare un valore di proprietà, il nuovo valore o lo stato dell'oggetto può essere verificato rispetto a una serie di condizioni preliminari o invarianti.
  • Un metodo get di proprietà può esistere per comodità, se il recupero del valore della proprietà può essere logicamente considerato equivalente al recupero di un valore di campo.
  • Un metodo di set di proprietà può eseguire altre operazioni, come la notifica a un oggetto padre o l'ascolto di oggetti di una modifica a un valore di proprietà.

Poiché le proprietà sono l'astrazione dei campi e, per comodità sintattica, linguaggi come C # hanno adottato la sintassi dei campi per le proprietà.


2
Prima riga dell'articolo di Wikipedia. "Una proprietà, in alcuni linguaggi di programmazione orientati agli oggetti, è un tipo speciale di membro della classe ...". Quindi la tua prima frase è chiaramente sbagliata. E la parte rimanente non risponde alla domanda.
Doc Brown,

1
@DocBrown: risposta interessante. Molti articoli di Wikipedia sono chiaramente errati. Suppongo che stai difendendo l'autore di questo articolo specifico?
Frank Hileman,

1
Non tutte le funzionalità dei linguaggi di programmazione orientate agli oggetti sono correlate a concetti orientati agli oggetti.
Frank Hileman,

1
Ciò non cambia il fatto che non stai rispondendo alla domanda.
Doc Brown,

3
Va notato che non è solo il setter che è facoltativo. Puoi avere solo proprietà setter.
Telastyn,

2

È una questione di implementazione contro implicazioni . Le proprietà erano in OOP prima che C ++ o Java arrivassero sulla scena (erano lì, con alcune rugosità intorno ai bordi, in Simula, e sono fondamentali per Smalltalk). Le entità con proprietà sono concettualmente diverse dai valori con il codice allegato. I prefissi get & set in alcune convenzioni linguistiche servono solo a confondere le acque; ti rendono consapevole della differenza tra campi e proprietà, supponendo che sia possibile accedere direttamente ai campi senza ottenere / impostare in un modo idiomatico per la lingua, e che perde.

Il punto centrale di OOP è trattare le cose come se fossero entità nel mondo "reale", non solo come strutture con un po 'di codice mischiato. Un altro programmatore dovrebbe avere bisogno di sapere molto, molto poco sul modo in cui ho implementato le cose, e non dovrebbe preoccuparsi affatto di quale dei vari valori sono autorizzati a ottenere e / o impostare sono reali e quali sono virtuali. Se ti imbatti in un mio vettore, non dovresti sapere se sto memorizzando angolo e magnitudine o componenti reali e immaginari interni all'oggetto vettoriale. Se cambio la rappresentazione in V2.0 della mia libreria, ciò non dovrebbe influire affatto sul tuo codice (anche se potresti voler sfruttare le nuove fantastiche funzionalità). Allo stesso modo, ci sono proprietà che un'entità potrebbe avere che dipendono da dati esterni all'entità, ma che sono indubbiamente proprietà dal punto di vista lessicale. Chiedi alle persone "quanti anni hai", non "per favore esegui il calcolo che mi rivelerà la tua età", anche se sai che i dati disponibili per quell'oggetto sono la data di nascita (un membro immutabile privato) e oggi data (una proprietà ambientale pubblica, auto-incrementante, dipendente dal fuso orario, dall'ora legale e dalla linea di data internazionale). L'età è una proprietà, non un metodo, anche se ci vuole un po 'di calcolo per arrivarci e non può (tranne che nelle rappresentazioni al computer del giocattolo rappresentazioni di cose con tempi di vita artificialmente limitati) essere memorizzate come un campo. anche se sai che i dati disponibili per quell'oggetto sono la data di nascita (un membro immutabile privato) e la data odierna (una proprietà ambientale pubblica, auto-incrementante, dipendente dal fuso orario, dall'ora legale e dalla linea di data internazionale ). L'età è una proprietà, non un metodo, anche se ci vuole un po 'di calcolo per arrivarci e non può (tranne che nelle rappresentazioni al computer del giocattolo rappresentazioni di cose con tempi di vita artificialmente limitati) essere memorizzate come un campo. anche se sai che i dati disponibili per quell'oggetto sono la data di nascita (un membro immutabile privato) e la data odierna (una proprietà ambientale pubblica, auto-incrementante, dipendente dal fuso orario, dall'ora legale e dalla linea di data internazionale ). L'età è una proprietà, non un metodo, anche se ci vuole un po 'di calcolo per arrivarci e non può (tranne che nelle rappresentazioni al computer del giocattolo rappresentazioni di cose con tempi di vita artificialmente limitati) essere memorizzate come un campo.

Piuttosto che pensare alle proprietà come al figlio bastardo di campi e metodi, è molto più soddisfacente alla cosa dei metodi come a un tipo specializzato di proprietà - cose che le tue entità possono fare piuttosto che cose che sono. Altrimenti non hai a che fare concettualmente con oggetti / entità, hai a che fare con raccolte di dati a cui è capitato di avere del codice. Le implementazioni possono essere identiche, ma le implicazioni sono diverse.

Inutile dire, tuttavia, che questa astrazione ha un costo. Se un programmatore che utilizza una classe non è in grado di dire se sta accedendo ai dati man mano che vengono archiviati o ottenendo / impostando valori che devono essere calcolati, allora ci sarà un livello al quale anche la lingua è necessariamente incerta (e quindi potrebbe richiedono che tutto richieda un codice intermedio tra accessori / selettori e valori). Non c'è nulla di concettualmente sbagliato nelle "strutture con codice" - possono certamente essere molto più efficienti - ma perdono l'implementazione ovunque, e questa è una delle cose che OOP dovrebbe eliminare.


Sono d'accordo con alcuni punti e in disaccordo con gli altri, ma il messaggio generale è una buona: Alcuni dati su un bisogni oggetto da calcolare, ma è ancora tecnicamente informazioni che è invece di un'azione che può essere fatto .
Pharap,

0

Assolutamente niente. Proprietà e OOP non hanno nulla a che fare l'una con l'altra. Le proprietà non sono altro che zucchero sintattico per le chiamate di funzione, e quindi hanno esattamente lo stesso attaccamento OOP che le chiamate di funzione fanno, vale a dire nessuna.

A proposito, Wikipedia è completamente errata. Il modello getMember / setMember che vedi in Java offre esattamente gli stessi vantaggi (e svantaggi) delle proprietà in C #. E puoi replicare questo modello anche in C se vuoi.

Le proprietà in C # non sono altro che zucchero sintattico supportato dal linguaggio.


3
Hai mai visto il concetto di proprietà in un linguaggio di programmazione al di fuori di un contesto di classe o oggetto? Non ho.
Doc Brown,

1
@DocBrown: l'ho implementato. Il fatto è che le proprietà sono obiettivi di valore piuttosto basso per gli autori del linguaggio, poiché il loro miglioramento rispetto alle normali chiamate di funzione è basso.
DeadMG

1
OP stava chiedendo la storia delle proprietà come concetto nei linguaggi di programmazione popolari. E in realtà, nel senso storico, esiste una connessione tra proprietà e OOP.
Doc Brown,

2
Forse sono stato un po 'avventato per attribuire questo concetto di proprietà al paradigma OOP in sé, ma come concetto trascende certamente le singole lingue e le loro caratteristiche. Forse sto lottando per articolare l'ontologia appropriata tra i due. Non sto suggerendo attraverso il titolo della domanda che le proprietà sono una caratteristica / concetto fondamentale di OOP che rende o rompe il formalismo di OOP, eppure sento che hanno solo una realtà in questo spazio OOP, motivo per cui ho definito la domanda come tale .
jxramos,

4
Non sono solo zucchero di sintassi in C #, esistono nei metadati dell'assembly come membri distinti e puoi fare cose con proprietà che non puoi con campi, come il database.
Andy,
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.