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

11

Sono venuto da uno sfondo C ++ e sto facendo di tutto C # nel mio attuale lavoro e ho appena letto molto Q & A su quale sia la differenza tra campi pubblici e proprietà e tutto il back and forth in variazioni e incarnazioni di questa domanda di base (ad es. 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 opportuno affrontare questo argomento in termini di ciò che i progettisti di tutte le lingue che hanno deciso di supportare proprietà nel primo luogo pensavo (controlla la lista nell'articolo di Wikipedia qui ). Come OOP si è evoluto da C ++ / Java per estendersi a ciò che l'articolo di Wikipedia identifica in modo interessante come una via di mezzo tra metodi e dati dei membri:

"That is, properties are intermediate between member code (methods) and member data (instance variables) of the class, and properties provide a higher level of encapsulation than public fields."

MSDN aggiunge ulteriore background:

"Although properties are technically very similar to methods, they are quite different in terms of their usage scenarios. They should be seen as smart fields. They have the calling syntax of fields, and the flexibility of methods."

Mi piacerebbe sapere come è arrivato che questo livello intermedio di incapsulamento si è dimostrato utile per la programmazione in generale. Presumo che questo concetto non fosse presente alla prima incarnazione dei linguaggi di programmazione che esprimeva il paradigma OOP.

    
posta jxramos 23.12.2014 - 23:41
fonte

7 risposte

5

Riguarda l'incapsulazione e il 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. Oppure se la vedi dal lato del mittente: il mittente dovrebbe essere in grado di accedere ai dati esistenti o eseguire un metodo attraverso un'interfaccia uniforme.

Ci sono diversi modi per ottenere ciò:

  • elimina del tutto i dati, usa solo i metodi (Newspeak fa questo)

    • una forma meno radicale di quanto sopra: sbarazzarsi dei dati nell'interfaccia pubblica , cioè rendere i dati sempre privati, nell'interfaccia pubblica, solo esporre i metodi (Smalltalk, Ruby fai questo)
  • eliminare del tutto i metodi, basta avere dati (Self fa questo, "metodi" sono solo Method oggetti assegnati alle variabili di istanza, le variabili di istanza sono ricercate con dispatch virtuale)

  • non fa distinzione sintattica o semantica tra metodi e dati (Scala lo fa, accedere a un campo è sintatticamente indistinguibile dal chiamare un metodo senza un elenco di argomenti ( foo.bar ), l'assegnazione a un campo è sintatticamente indistinguibile dal chiamare un metodo appositamente denominato ( foo.bar = baz ) è uguale a foo.bar_=(baz) , ovvero chiama un metodo denominato foo_= , e i valori di sola lettura possono essere sovrascritti o implementati da un metodo senza elenco parametri (cioè val foo ) in una superclasse può essere sovrascritto (o un abstract val essere 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 campi e metodi sono semanticamente e sintatticamente distinti.

C # cerca di risolvere questo problema aggiungendo proprietà al linguaggio, fondamentalmente metodi che assomigliano a campi. Tuttavia, le chiamate al metodo appaiono ancora diverse rispetto agli accessi di campi e proprietà. Campi e proprietà ora hanno accesso uniforme, ma i metodi ancora non lo fanno.

Quindi, questo in realtà non risolve il problema: non è possibile risolvere il problema avendo due modi diversi per accedere alle cose aggiungendo un terzo modo per accedere alle cose! Anche se quella terza via assomiglia a uno degli altri due modi, avrai ancora (almeno) due modi diversi. Puoi risolverlo solo eliminando tutti i diversi modi tranne uno o eliminando le differenze.

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

    
risposta data 24.12.2014 - 01:56
fonte
18

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

Credo che questa sia stata la ragione principale per cui i progettisti linguistici hanno deciso di aggiungere dello zucchero sintattico per ridurre il rumore. E sebbene le proprietà non siano sicuramente un "concetto OO di base", hanno almeno qualcosa da fare con l'orientamento agli oggetti. Non mostrano "un'evoluzione di OOP" (come presuppone il titolo della domanda), ma supportano la modellazione di OO a livello di linguaggio di programmazione per semplificare l'implementazione.

    
risposta data 24.12.2014 - 00:11
fonte
11

Hai indietro (tipo di). Lambda Calculus esiste praticamente come base formale per i linguaggi di programmazione, ed è stato per decenni. Non ha campi.

Per modellare lo stato mutabile, è necessario creare 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 uno sfondo teorico , OO non si è evoluto per avere questa roba. OO leggi Linguaggi di programmazione 101 e fa un piccolo passo avanti.

Da una prospettiva pratica , ci sono due motivazioni abbastanza chiare. Vieni da uno sfondo C ++, quindi cosa dovrebbe accadere 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, fai blah"? Puoi uccidere quel campo, creare una funzione o due e collegare quella logica, dal momento che non puoi fidarti degli sviluppatori di chiamare "UpdateTextbox" loro stessi. Questa è una molto violazione della tua API (e sfortunatamente ancora una rottura nell'implementazione delle proprietà di .NET). Questo tipo di comportamento è tutto il posto nell'API di Windows. Dato che è un grosso problema per Microsoft, C # probabilmente voleva renderlo meno doloroso.

L'altra grande motivazione è Java Beans e i loro parenti. Sono stati creati numerosi framework per utilizzare la reflection Java per cercare GetX e SetX coppie e trattarli efficacemente come le proprietà moderne. Ma dal momento che non erano costrutti linguistici reali, questi quadri erano fragili e poco soddisfacenti. Se hai digitato un nome, le cose si interrompono silenziosamente. Se uno si è rifattorizzato, nulla ha spostato l'altro lato della proprietà. E fare tutto il campo / get / set boilerplate è stato prolisso e noioso (anche per Java!). Poiché C # è stato sviluppato in gran parte come "Java con lezioni apprese", quella sorta 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 enormemente l'adozione e, come strumento , i programmatori hanno scoperto che le proprietà risolvono un sottoinsieme di problemi in modo più pulito rispetto a funzioni o campi.

    
risposta data 24.12.2014 - 00:37
fonte
3

In .net, in particolare, le proprietà provengono dai vecchi giorni di Visual Basic che, come accade, non erano orientate agli oggetti nel modo in cui pensiamo oggi. È stato in gran parte costruito attorno al nuovo sistema COM che ha trattato superficialmente tutto non necessariamente come classi, ma in termini di componenti che esponevano proprietà a cui si poteva accedere sia nel codice che negli editor grafici. Quando VB e C # di nuova creazione sono stati uniti in .net, VB ha acquisito un sacco di funzioni OOP e ha mantenuto le proprietà dal momento della loro rimozione sarebbe come un passo indietro - immagina se lo strumento di aggiornamento automatico del codice che avevano in Visual Studio fosse stato sostituendo tutte le tue proprietà con getter e setter e rompendo la compatibilità con tutte le librerie COM. Sarebbe logico supportarli in tutti i linguaggi .net in modo che i componenti possano essere utilizzati in tutto il framework senza problemi di interoperabilità o esporre l'implementazione interna.

    
risposta data 24.12.2014 - 05:42
fonte
3

Le proprietà non hanno nulla a che fare con la programmazione orientata agli oggetti, perché le proprietà sono solo zucchero sintattico. Le proprietà sembrano superficiali e, nel mondo .net, si raccomanda che si comportino come i 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. O il metodo set o il metodo get possono essere omessi, ma non entrambi. Potrebbe non esserci nessun campo che memorizza il valore restituito dal metodo get. Poiché condividono una sintassi con i campi e poiché utilizzano spesso campi, le persone associano le proprietà ai campi.

Le proprietà hanno vantaggi rispetto ai campi:

  • In un metodo set di proprietà, prima di memorizzare un valore di proprietà, il nuovo valore o lo stato dell'oggetto può essere verificato rispetto a un insieme di precondizioni o invarianti.
  • Un metodo di ottenimento di proprietà può esistere per comodità, se il recupero del valore della proprietà può essere considerato logicamente equivalente al recupero di un valore di campo.
  • Un metodo set di proprietà può eseguire altre operazioni, ad esempio la notifica di un oggetto padre o di oggetti di ascolto 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 del campo per le proprietà.

    
risposta data 23.12.2014 - 23:49
fonte
2

È una questione di implementazione contro implicazione . Le proprietà erano in OOP prima che C ++ o Java colpissero la scena (erano lì, con una certa ruvidezza ai bordi, in Simula, e sono fondamentali per Smalltalk). Le entità con proprietà sono concettualmente diverse dai valori con il codice allegato. Il get & impostare prefissi in alcune convenzioni linguistiche servono solo a confondere le acque; ti rendono consapevole della differenza tra campi e proprietà, supponendo che i campi possano essere letti direttamente senza get / set in un modo che è idiomatico al linguaggio, e che perde.

L'intero punto di OOP è trattare le cose come se fossero entità nel mondo "reale", non solo come strutture con qualche codice mescolato in. Un altro programmatore dovrebbe avere bisogno di sapere molto, molto poco sul modo in cui ho implementato cose, e non dovrebbe preoccuparsi di quale dei vari valori sono autorizzati a ottenere e / o impostare sono reali e quali sono virtuali. Se attraversi un mio vettore, non dovresti sapere se sto memorizzando l'angolo e la grandezza o componenti reali e immaginari interni all'oggetto vettoriale. Se cambio la rappresentazione nella V2.0 della mia libreria, non dovrebbe influenzare il tuo codice (anche se potresti voler approfittare delle 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à da un punto di vista lessicale. Chiedi alle persone "quanti anni hai", non "per favore esegui il calcolo che rivelerà la tua età per me", 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, autoincrementante, dipendente dal fuso orario, dall'ora legale e dalla linea della data internazionale). L'età è una proprietà, non un metodo, anche se ci vuole un po 'di calcoli per arrivare lì e non può (tranne che nelle rappresentazioni di computer giocattolo di cose con vite limitate artificialmente) essere archiviati come un campo.

Piuttosto che pensare alle proprietà come figli bastardi di campi e metodi, è molto più soddisfacente per i metodi come un tipo specializzato di proprietà - cose che le tue entità possono fare piuttosto che cose che sono. Altrimenti non stai trattando concettualmente di oggetti / entità, hai a che fare con raccolte di dati a cui è stato assegnato un codice. implementaions potrebbe essere identico, ma le implicazioni sono diverse.

Dovrebbe essere inutile dire, tuttavia, che questa astrazione ha un costo. Se un programmatore che usa una classe non può dire se sta accedendo ai dati mentre è memorizzato o sta ottenendo / impostando i valori che devono essere calcolati, allora ci sarà un livello in cui la lingua è anche necessariamente incerta (e quindi potrebbe richiede che tutto richieda un codice intermedio tra accessori / selettori e valori). Non c'è nulla di teoricamente sbagliato in "struct with code" - possono certamente essere molto più efficienti - ma perdono l'implementazione ovunque, e questa è una delle cose che l'OOP dovrebbe eliminare.

    
risposta data 24.12.2014 - 05:05
fonte
0

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

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

Le proprietà in C # non sono altro che lo zucchero sintattico supportato dalla lingua.

    
risposta data 24.12.2014 - 00:05
fonte

Leggi altre domande sui tag