Abbiamo davvero bisogno delle lingue OO per gestire la complessità del software?


209

Questa sarà una domanda delicata, non tecnica, e non sono sicuro che questa sia la piattaforma giusta. Ma sono uno studente CS iniziale quindi spero che lo tolleriate.

Nel primo semestre ci sono stati introdotti concetti OOP come incapsulamento, nascondimento dei dati, modularità, eredità e così via attraverso Java e UML. (Java è il mio primo linguaggio di programmazione)

Per come la capisco, OOP è un modo di gestire la complessità del software. Ma i suoi principi non sono nuovi o unici, sono in un certo senso universali per tutti i campi dell'ingegneria.

Ad esempio un'auto è una struttura molto complessa la cui complessità è gestita da una gerarchia di componenti modulari e incapsulati con comportamenti e interfacce ben definiti.

Ma non capisco il motivo dietro l'introduzione di un nuovo paradigma di programmazione. Penso che tutti i principi utilizzati per gestire la complessità possano essere realizzati con linguaggi di programmazione procedurali. Ad esempio, per la modularità possiamo semplicemente dividere il programma in molti piccoli programmi che eseguono attività ben definite il cui codice è contenuto in file separati. Questi programmi interagirebbero tra loro attraverso i loro input e output ben definiti. I file possono essere protetti (crittografati?) Per ottenere l'incapsulamento. Per il riutilizzo del codice possiamo semplicemente chiamare quei file ogni volta che sono necessari in nuovi programmi. Questo non cattura tutto ciò che è OOP o mi sto perdendo qualcosa di molto ovvio?

Non sto chiedendo una prova che OOP gestisca la complessità. Secondo me lo fa sicuramente. Ma penso che tutti i principi utilizzati per gestire la complessità come la modularità, l'incapsulamento, il nascondimento dei dati e così via possano essere facilmente implementati dai linguaggi procedurali. Allora perché davvero OOP se possiamo gestire la complessità senza di essa?


41
Manca la separazione tra interfaccia e implementazione. Essere in grado di scambiare un'implementazione con un'altra in fase di esecuzione è una caratteristica molto importante. Fondamentalmente, ciò si ottiene inviando il metodo dinamico dei linguaggi OO con ereditarietà. Anche i linguaggi procedurali possono farlo (leggi: puntatori vuoti), ma senza la sicurezza del tipo.
Marstato,

81
In larga misura, l'idea di linguaggi e design orientati agli oggetti è precisamente quella di rendere quei concetti universali e intuitivi il più facili possibile da rappresentare e ricreare nel codice. Se avessi uno schema o una serie di linee guida su come raggiungere tutte quelle cose senza un linguaggio intrinsecamente orientato agli oggetti, le tue proposte su come fare le cose sarebbero effettivamente la metodologia orientata agli oggetti utilizzata. Le lingue OO effettive sono solo un modo per formalizzare e semplificare ciò.
Standback

14
@RobbieDee hai letto davvero la mia domanda? Si tratta di cercare di comprendere OO a un livello più fondamentale mettendo in dubbio il tempo in cui la complessità del software può essere gestita senza OO. Non sto cercando di minare OO, non sto cercando di inventare qualcosa di nuovo, sto solo cercando di capirlo meglio e se la domanda è così "evidente" perché ha ricevuto l'eccellente risposta da Jorg?
Scambia il cambio di

12
La crittografia di un file non è incapsulamento. Potresti aver oscurato la visualizzazione dei contenuti del codice da un altro sviluppatore, ma non hai necessariamente protetto il funzionamento interno del codice da altri codici. L'autore originale potrebbe farlo prima o dopo la crittografia se riesce a ricordare come.
JeffO,

8
Non hai bisogno di nulla oltre al linguaggio macchina: lascia che il programmatore memorizzi i codici operativi e scriva da solo quelli e gli zeri. Ma avere una sorta di linguaggio "simbolico" è molto utile in termini di riduzione degli errori e aumento della produttività e, come ha osservato Dijkstra, un linguaggio che impone una "struttura" (o almeno rende più facile il mantenimento della "struttura") aiuta notevolmente. Le lingue OO potrebbero non essere la tecnologia ideale, dato l'attuale livello di sofisticazione linguistica, ma sono abbastanza buone per molte applicazioni. L'idea è di gestire la complessità senza ostacolarti.
Daniel R Hicks,

Risposte:


177

Fammi provare con una risposta teorica molto bassa :)

Quello che stai veramente chiedendo è: perché includere il supporto per l'Orientamento degli oggetti (OO) direttamente nella lingua quando i linguaggi procedurali possono essere usati per progettare e scrivere il codice OO?

E la risposta è: avere uno standard per come OO è espresso nel codice sorgente in modo da non finire con 22 implementazioni diverse per la stessa astrazione.

Ad esempio, supponiamo che crei un MagicButtone un MagicSliderche può essere utilizzato in un sistema di interfaccia utente. Ho bisogno di un modo per raggruppare i metodi che possono essere utilizzati con MagicButton, i metodi che possono essere utilizzati solo con MagicSlider e i metodi che possono essere utilizzati da entrambi. Questi oggetti condividono alcuni metodi perché sono entrambi oggetti Magic Gui.

Posso fare il raggruppamento nominando le funzioni in un modo speciale MagicSlider_DoSomething ..., includendo i metodi in file specifici nominati in un modo speciale MagicSliderMethods.XXX, oppure potrei trovare un altro modo speciale per fare la stessa cosa. Se non esiste un modo standard nella lingua per farlo, lo farò diversamente da te e in modo diverso da chiunque altro. Ciò rende la condivisione del codice molto più difficile.

Sì, l'invio tardivo - metodi virtuali nei linguaggi OO - può essere implementato nei linguaggi procedurali, ma ci sono molti modi diversi per implementarlo. A seconda di chi ha scritto il codice finirai con diverse implementazioni di OO all'interno dello stesso programma.

Pensa al cattivo sviluppatore di manutenzione. Questa persona deve gestire diverse astrazioni di oggetti e diversi modi per chiamare metodi virtuali a seconda di chi ha scritto il codice originale.

Inoltre: avere le astrazioni nella lingua consente agli editor di codice avanzati come Eclipse di eseguire molte analisi statiche sul codice. Ad esempio Eclipse può offrire un elenco di tutti i metodi che possono essere utilizzati su un oggetto, nonché l'implementazione automatica di "metodi TODO" vuoti. Eclispe sa esattamente quali metodi la tua classe deve implementare in base a quali classi estendi e quali interfacce implementi. Ciò sarebbe quasi impossibile se non ci fosse uno standard linguistico per eseguire OO.


40
Esempio classico: Lua. Non è nativo OO, ma può essere fatto, ma questo significa che ci sono circa 5 diverse librerie OO altrettanto conosciute che non sono completamente interoperabili.
Kroltan,

55
@steakexchange Ti concentri troppo sugli assoluti. Molto poco ha un "unico scopo". Tutte le lingue fanno molte cose diverse con diversi gradi di qualità. Scegliere una lingua è scegliere l'insieme di compromessi che lo rendono più adatto allo scopo per il quale ne hai bisogno.
Tim B

42
@nocomprende La standardizzazione delle astrazioni è quasi letteralmente a cui servono i linguaggi di programmazione. Perfino il linguaggio assembly si sottrae alle differenze tra qualcosa come dieci generazioni di hardware in un decennio e mezzo.
David Moles,

56
@DavidMoles Le astrazioni standardizzate sono letteralmente i linguaggi di programmazione. Non perdere l'occasione perfetta per usare "letteralmente" letteralmente!
Clemente Cherlin,

12
È possibile standardizzare questo. Quando ero all'università a metà degli anni '90, ho fatto una quantità abbastanza consistente di lavoro in X-Windows (principalmente basato su Motif, per coloro che ricordano queste cose). X-Windows ha effettivamente consentono di implementare tutte le funzioni di orientamento oggetto di regolare C . La ginnastica mentale per farlo era piuttosto sostanziale, e faceva molto affidamento su persone che non guardavano dentro la scatola (a quel punto il Codice Widget di Schroedinger generalmente finiva per essere morto). I linguaggi OO lo nascondono ai programmatori, come fa un normale compilatore per l'assemblatore, e la vita è più semplice.
Graham,

211

Nel primo semestre ci sono stati introdotti concetti OOP come incapsulamento, nascondimento dei dati, modularità, eredità e così via attraverso Java e UML. (Java è il mio primo linguaggio di programmazione)

Nessuno di questi sono concetti OOP. Esistono tutti al di fuori di OO, indipendentemente da OO e molti addirittura sono stati inventati prima di OO.

Quindi, se pensi che questo sia OO, allora la tua conclusione è giusta: puoi fare tutto ciò nei linguaggi procedurali, perché non hanno nulla a che fare con OO .

Ad esempio, uno dei documenti fondamentali sulla modularità è sui criteri da utilizzare per la decomposizione dei sistemi in moduli . Non c'è menzione di OO lì dentro. (Fu scritto nel 1972, a quel tempo OO era ancora una nicchia oscura, nonostante avesse già più di un decennio.)

Sebbene l' astrazione dei dati sia importante in OO, è più una conseguenza della funzionalità primaria di OO (messaggistica) che non una funzione di definizione. Inoltre, è molto importante ricordare che esistono diversi tipi di astrazione dei dati. I due tipi più comuni di astrazione dei dati attualmente in uso (se ignoriamo "nessuna astrazione di sorta", che è probabilmente ancora utilizzata più delle altre due combinate), sono i tipi di dati astratti e gli oggetti . Quindi, semplicemente dicendo "Informazioni nascoste", "Incapsulamento" e "Astrazione dei dati", non hai detto nulla su OO, poiché OO è solo una forma di astrazione dei dati, e i due sono in realtà fondamentalmente diversi:

  • Con i tipi di dati astratti, il meccanismo per l'astrazione è il sistema dei tipi ; è il sistema di tipi che nasconde l'implementazione. (Il sistema dei tipi non deve necessariamente essere statico.) Con Oggetti, l'implementazione è nascosta dietro un'interfaccia procedurale , che non richiede tipi. (Ad esempio, può essere implementato con chiusure, come avviene in ECMAScript.)
  • Con i tipi di dati astratti, le istanze di ADT diversi sono incapsulate l'una dall'altra, ma le istanze dello stesso ADT possono ispezionare e accedere reciprocamente alla rappresentazione e all'implementazione privata. Gli oggetti sono sempre incapsulati da tutto . Solo l'oggetto stesso può ispezionare la propria rappresentazione e accedere alla propria implementazione privata. Nessun altro oggetto , nemmeno altri oggetti dello stesso tipo, altre istanze della stessa classe, altri oggetti con lo stesso prototipo, cloni dell'oggetto o qualsiasi altra cosa possano farlo. Nessuno .

Ciò significa, in ogni caso, che in Java le classi non sono orientate agli oggetti. Due istanze della stessa classe possono accedere reciprocamente alla rappresentazione e all'implementazione privata. Pertanto, le istanze delle classi non sono oggetti, in realtà sono istanze ADT. Java interfaces, tuttavia, non forniscono l'astrazione dei dati orientato agli oggetti. Quindi, in altre parole: solo le istanze di interfacce sono oggetti in Java, mentre le istanze di classi no.

Fondamentalmente, per i tipi, è possibile utilizzare solo interfacce. Ciò significa che i tipi di parametri di metodi e costruttori, i tipi restituiti di metodi, i tipi di campi di istanza, i campi statici e i campi locali, l'argomento per un instanceofoperatore o un operatore di cast e gli argomenti di tipo per un costruttore di tipo generico devono sempre essere interfacce. Una classe può essere utilizzata solo direttamente dopo l' newoperatore, da nessun'altra parte.

Ad esempio, per la modularità possiamo semplicemente dividere il programma in molti piccoli programmi che eseguono attività ben definite il cui codice è contenuto in file separati. Questi programmi interagirebbero tra loro attraverso i loro input e output ben definiti. I file possono essere protetti (crittografati?) Per ottenere l'incapsulamento. Per il riutilizzo del codice possiamo semplicemente chiamare quei file ogni volta che sono necessari in nuovi programmi. Questo non cattura tutto ciò che è OOP o mi sto perdendo qualcosa di molto ovvio?

Quello che descrivi è OO.

Questo è davvero un buon modo di pensare a OO. In realtà, è esattamente quello che gli inventori originali di OO avevano in mente. (Alan Kay ha fatto un ulteriore passo avanti: ha immaginato un sacco di piccoli computer che si scambiano messaggi attraverso la rete.) Quello che chiami "programma" è di solito chiamato "oggetto" e invece di "chiamata" di solito diciamo "invia un messaggio ".

L'orientamento agli oggetti è tutto incentrato sulla messaggistica ( nota anche come invio dinamico ). Il termine "Object Oriented" è stato coniato dal Dr. Alan Kay, il principale designer di Smalltalk, e lo definisce così :

OOP per me significa solo messaggistica, conservazione locale, protezione e occultamento del processo statale ed estremo vincolo tardivo di tutte le cose.

Analizziamo questo:

  • messaggistica ("invio metodo virtuale", se non si ha familiarità con Smalltalk)
  • il processo statale dovrebbe essere
    • mantenuto localmente
    • protetta
    • nascosto
  • estremo legame tardivo di tutte le cose

Dal punto di vista dell'implementazione, la messaggistica è una chiamata di procedura in ritardo e, se le chiamate di procedura sono in ritardo, non è possibile sapere in fase di progettazione ciò che si intende chiamare, quindi non è possibile fare ipotesi sulla rappresentazione concreta dello stato. Quindi, in realtà si tratta di messaggistica, il late-binding è un'implementazione della messaggistica e l'incapsulamento ne è una conseguenza.

In seguito ha chiarito che " La grande idea è" messaggistica ", e si rammarica di averla definita" orientata agli oggetti "anziché" orientata ai messaggi ", poiché il termine" orientato agli oggetti "pone l'accento sulla cosa non importante (oggetti ) e distrae da ciò che è veramente importante (messaggistica):

Solo un gentile promemoria che ho fatto un po 'di fatica all'ultimo OOPSLA per cercare di ricordare a tutti che Smalltalk NON è solo la sua sintassi o la libreria di classi, non si tratta nemmeno di classi. Mi dispiace di aver coniato molto tempo fa il termine "oggetti" per questo argomento perché molte persone si concentrano sull'idea minore.

La grande idea è "messaggistica" - ecco di cosa si occupa il kernal di Smalltalk / Squeak (ed è qualcosa che non è mai stato del tutto completato nella nostra fase PARC Xerox). I giapponesi hanno una piccola parola - ma - per "ciò che sta in mezzo" - forse l'equivalente inglese più vicino è "interstiziale". La chiave per realizzare sistemi grandi e coltivabili è molto di più per progettare come comunicano i suoi moduli piuttosto che quali dovrebbero essere le loro proprietà e comportamenti interni. Pensa a Internet: per vivere, (a) deve consentire molti diversi tipi di idee e realizzazioni che vanno oltre ogni singolo standard e (b) per consentire vari gradi di interoperabilità sicura tra queste idee.

(Certo, oggi, la maggior parte delle persone non si concentra nemmeno sugli oggetti ma sulle classi, il che è ancora più sbagliato.)

La messaggistica è fondamentale per OO, sia come metafora che come meccanismo.

Se invii a qualcuno un messaggio, non sai cosa ci fanno. L' unica cosa che puoi osservare è la loro risposta. Non sai se hanno elaborato il messaggio da soli (cioè se l'oggetto ha un metodo), se hanno inoltrato il messaggio a qualcun altro (delega / proxy), se lo hanno persino capito. Ecco cos'è l'incapsulamento, questo è OO. Non puoi nemmeno distinguere un proxy dalla realtà, purché risponda a come ti aspetti.

Un termine più "moderno" per "messaggistica" è "invio dinamico del metodo" o "chiamata del metodo virtuale", ma che perde la metafora e si concentra sul meccanismo.

Quindi, ci sono due modi per guardare la definizione di Alan Kay: se la guardi da sola, potresti osservare che la messaggistica è fondamentalmente una chiamata di procedura in ritardo e l'associazione in ritardo implica l'incapsulamento, quindi possiamo concludere che # 1 e # 2 sono in realtà ridondanti, e OO si basa sul late-binding.

Tuttavia, in seguito ha chiarito che la cosa importante è la messaggistica, e quindi possiamo guardarla da una prospettiva diversa: la messaggistica è in ritardo. Ora, se la messaggistica fosse l' unica cosa possibile, allora il n. 3 sarebbe banalmente vero: se c'è solo una cosa, e quella cosa è in ritardo, allora tutte le cose sono in ritardo. E ancora una volta, l'incapsulamento segue dalla messaggistica.

Punti simili sono stati anche sottolineati in On Understanding Data Abstraction, rivisitato da William R. Cook e anche nella sua proposta di definizioni semplificate e moderne di "oggetto" e "oggetto orientato" :

L'invio dinamico delle operazioni è la caratteristica essenziale degli oggetti. Significa che l'operazione da invocare è una proprietà dinamica dell'oggetto stesso. Le operazioni non possono essere identificate staticamente e in generale non è possibile [sapere] esattamente quale operazione verrà eseguita in risposta a una determinata richiesta, tranne eseguendola. Questo è esattamente lo stesso delle funzioni di prima classe, che vengono sempre inviate in modo dinamico.

In Smalltalk-72 non c'erano nemmeno oggetti! C'erano solo flussi di messaggi che venivano analizzati, riscritti e reindirizzati. Prima sono arrivati ​​i metodi (metodi standard per analizzare e reindirizzare i flussi di messaggi), successivamente sono arrivati ​​gli oggetti (raggruppamenti di metodi che condividono un certo stato privato). L'eredità è arrivata molto più tardi e le classi sono state introdotte solo come un modo per sostenere l'eredità. Se il gruppo di ricerca di Kay avesse già saputo dei prototipi, probabilmente non avrebbero mai introdotto le classi.

Benjamin Pierce in Tipi e linguaggi di programmazione sostiene che la caratteristica principale di Orientamento agli oggetti è la ricorsione aperta .

Quindi: secondo Alan Kay, OO si occupa di messaggistica. Secondo William Cook, OO si basa sulla spedizione di metodi dinamici (che è davvero la stessa cosa). Secondo Benjamin Pierce, OO è tutto su Open Recursion, il che significa sostanzialmente che gli auto-riferimenti vengono risolti dinamicamente (o almeno è un modo di pensare), o, in altre parole, i messaggi.

Come puoi vedere, la persona che ha coniato il termine "OO" ha una visione piuttosto metafisica degli oggetti, Cook ha una visione piuttosto pragmatica e Pierce una visione matematica molto rigorosa. Ma la cosa importante è: il filosofo, il pragmatico e il teorico sono tutti d'accordo! La messaggistica è il pilastro di OO. Periodo.

Nota che qui non si parla di eredità! L'ereditarietà non è essenziale per OO. In generale, la maggior parte dei linguaggi OO ha un modo per riutilizzare l'implementazione, ma ciò non deve necessariamente essere eredità. Potrebbe anche essere una qualche forma di delega, per esempio. In effetti, il Trattato di Orlando tratta la delega come alternativa all'eredità e in che modo diverse forme di delega ed eredità portano a diversi punti di progettazione all'interno dello spazio di progettazione di linguaggi orientati agli oggetti. (Si noti che in realtà anche nelle lingue che supportano l'ereditarietà, come Java, alle persone viene effettivamente insegnato ad evitarlo, indicando di nuovo che non è necessario per OO.)


16
+100 - Diamo la colpa intrinseca alle cose perché vengono usate in modo improprio.
JeffO,

55
Mi dispiace, ma è incredibilmente sbagliato. Alan Kay potrebbe aver escogitato il termine, ma i principi erano in circolazione prima di Smalltalk. La programmazione orientata agli oggetti deriva da Simula e il suo stile OO non aveva nulla a che fare con i "messaggi". Praticamente tutti i linguaggi OO che hanno avuto successo sono basati sui principi di base stabiliti in Simula - gli stessi che vediamo in Java - e lo stile OO di Smalltalk è stato un fallimento nel "mercato delle idee" ogni volta che viene reintrodotto, perché semplicemente non funziona molto bene. Il nome era l' unica cosa veramente significativa che Kay ha contribuito.
Mason Wheeler,

23
@steakexchange No. "L'essenza di OO", la cosa che lo rende veramente distintivo, sono gli oggetti con metodi virtuali. C'è un motivo per cui nessuno usa Smalltalk: il sistema di trasmissione dei messaggi funziona molto male su scala individuale. Ogni volta che un progettista linguistico ben intenzionato ma ingenuo cerca di reimplementare i principi di Smalltalk, finisce per fallire. (L'esempio più recente sarebbe Objective-C, che nessuno avrebbe mai usato se Steve Jobs non l'avesse spinto in gola a tutta la comunità iOS. Non ha mai trovato trazione al di fuori dell'ecosistema Apple, e c'è una ragione per questo. )
Mason Wheeler,

28
@MasonWheeler Potresti forse approfondire il tuo commento in una risposta dal momento che hai una visione completamente opposta a ciò che Jorg sta dicendo?
cambio di battello

20
Vale anche la pena notare che il concetto di linguaggi orientati agli oggetti si è evoluto molto. Questi concetti ancestrali potrebbero non essere così veri al giorno d'oggi con molte lingue che abbandonano i vecchi modelli e abbracciano i multi-paradigmi. Guarda C #, per esempio - che il linguaggio confonde quasi tutto sotto il sole in una volta e, sebbene sia principalmente definito come linguaggio OO, in realtà è un mix di paradigmi diversi. Ciò gli consente di essere uno strumento davvero espressivo per gli sviluppatori di tutto il mondo. Inoltre, OO basato sulla classe è uno dei tanti ugualmente validi programmi di programmazione OO.
T. Sar,

66

Ma penso che tutti i principi utilizzati per gestire la complessità come la modularità, l'incapsulamento, il nascondimento dei dati e così via possano essere facilmente implementati dai linguaggi procedurali.

Quando dici "molto facilmente" stai facendo una dichiarazione molto audace. Il modo in cui lo leggo è: "Non vedo la difficoltà, quindi non deve essere molto grande." Quando viene formulato in questo modo, diventa chiaro che non stai chiedendo "perché abbiamo bisogno di OO", stai chiedendo "perché non sono immediatamente evidenti le difficoltà incontrate da altri paradigmi di programmazione che portano all'invenzione di OO? "

Una risposta a questa domanda è che molte di queste difficoltà non esistono nei tipi di programmi su cui stai lavorando. Non ti viene chiesto di aggiornare il codice spaghetti di 40 anni. Non si sta tentando di scrivere un nuovo display manager per un sistema operativo. Non stai eseguendo il debug di applicazioni distribuite multithread.

Per molti dei tipi di programmi giocattolo a cui gli studenti CS hanno il compito di scrivere, potremmo anche scriverli in BASIC o assembly come Java o Python. Questo perché la complessità intrinseca delle attività è così bassa, c'è solo uno sviluppatore, non ci sono problemi di interoperabilità legacy, le prestazioni non contano e il codice verrà probabilmente eseguito solo una manciata di volte su una macchina.

Immagina di prendere un autista studente e di chiedere loro di immergersi in una strada trafficata nelle ore di punta, su una trasmissione manuale senza sincronismo, salendo su una ripida collina. Disastro. Perché? Non sono in grado di gestire il livello di complessità richiesto per seguire contemporaneamente tutte le regole richieste dall'attività.

Ora immagina lo stesso studente, lo stesso veicolo, che guida a passo d'uomo in un parcheggio vuoto. Sono OK, perché il loro livello di abilità è adeguato al compito. Non c'è pressione, poco rischio e possono prendere le singole attività secondarie di avviamento, frizione, cambio di marcia, accelerazione, sterzata una alla volta.

Quello studente potrebbe chiedersi perché abbiamo trasmissioni automatiche, se un pilota esperto può fare tutte queste cose contemporaneamente? La risposta è che un pilota abbastanza esperto non ha bisogno, in condizioni ottimali, di un automatico. Ma non siamo tutti conducenti professionisti in condizioni ottimali e in genere desideriamo che i progettisti dell'auto si prendano cura di tutta quella complessità per noi.

Un programmatore abbastanza abile e disciplinato può effettivamente creare un sistema funzionante ad alta complessità in C, o assembly. Ma non siamo tutti Linus Torvalds. Né dovremmo essere, per creare software utile.

Personalmente non ho interesse a dover reinventare tutte le caratteristiche di un linguaggio moderno prima ancora di poter affrontare il problema. Se posso sfruttare un linguaggio che include soluzioni a problemi già risolti, perché non dovrei?

Quindi rivolgerò la tua domanda e ti chiederò se le lingue offrono funzionalità utili come l'incapsulamento e il polimorfismo, perché non dovremmo usarle?


13
Quindi, fondamentalmente, è possibile eseguire OO con un linguaggio procedurale, ma ciò sta facendo le cose manualmente mentre si utilizza un linguaggio OO standardizzato automatizza e semplifica.
Scambia il cambio di

6
@steakexchange Praticamente esattamente questo.
Tim B

3
@steakexchange un buon esempio storico di questo era il modello a oggetti per X Windows nel corso della giornata. È stato scritto in C ma era basato su un sistema orientato agli oggetti. Quindi, hai dovuto seguire alcune convenzioni per interfacciarti in modo che le tue lezioni andassero bene con quelle di tutti gli altri.
Ukko,

7
@nocomprende Certamente. Ma si potrebbe rendere il proprio computer non avviabile eseguendo scritture su disco non elaborate invece di fare affidamento sul filesystem, e sarà davvero difficile eseguire il debug dei problemi in un sistema ad hoc creato da un novizio. L'incapsulamento, se fatto correttamente, ci impedisce di intrometterci intenzionalmente o involontariamente con cose che non dovremmo.
Clemente Cherlin,

3
È interessante per me che gli esempi che dai di applicazioni che trarrebbero beneficio da OO spesso non sono scritti nelle lingue OO. Gli spaghetti di 40 anni sono probabilmente scritti in C, COBOL, FORTRAN o REXX. Il display manager è probabilmente scritto in C (sebbene con convenzioni OO-ish), e molti sistemi multithread distribuiti con successo sono scritti in Erlang, Go o C.
James_pic

22

Quello che stai descrivendo non è OOP, è l'astrazione. L'astrazione è presente in tutti i moderni modelli di design, anche in quelli che non sono OOP. E OOP è un tipo molto specifico di astrazione.

Innanzitutto, vale la pena notare che non esiste un'unica definizione di OOP, quindi potrebbero esserci persone che non sono d'accordo con ciò che sto definendo OOP.

In secondo luogo, è importante ricordare che OOP è stato ispirato da modelli tradizionali di design, quindi le somiglianze con il design delle auto non è una coincidenza.

Tuttavia, ecco alcuni modi in cui OOP è più sfumato di quello che hai detto:

  • Incapsulamento: non si tratta solo di avere un'interfaccia impostata per un modulo (ovvero l'astrazione), si tratta di vietare l'accesso oltre questa interfaccia. In Java, l'accesso a una variabile privata è un errore di compilazione, mentre nella progettazione della tua auto, puoi (in alcuni casi) usare le cose in modo diverso dall'interfaccia prevista.

  • Eredità: questa è davvero la cosa che rende unico OOP. Dopo aver definito un'interfaccia, è possibile eseguire più operazioni implementando tale interfaccia e si può fare ciò in modo gerarchico, alterando parti specifiche della loro implementazione, ereditando tutte le parti precedenti, riducendo in modo massiccio la duplicazione del codice.

    Se pensi in termini di componenti incapsulati di un'auto, non c'è davvero un equivalente a questo. Non c'è modo per me di creare una marcia prendendo una marcia diversa e cambiando una parte specifica della sua implementazione. (Almeno non la penso così, non so molto delle macchine).

  • Polimorfismo : una volta definita un'interfaccia, tutto ciò che utilizza tale interfaccia dovrebbe essere indistinguibile, dal punto di vista delle operazioni disponibili, e non dovresti avere bisogno di sapere quale implementazione viene utilizzata per utilizzare un'interfaccia. È qui che diventano importanti il sottotipo e il Principio di sostituzione di Liskov .

  • Accoppiamento : un aspetto chiave di OOP è che mettiamo in stretta relazione le cose con le stesse operazioni e distribuiamo le diverse forme che possono avere. I dati sono raggruppati con operazioni su tali dati. Ciò significa che è molto facile aggiungere una nuova forma di dati (una nuova implementazione), ma è molto difficile aggiungere una nuova operazione a un'interfaccia (poiché dovresti aggiornare ogni classe che implementa l'interfaccia). Ciò è in contrasto con i tipi di dati algebrici nei linguaggi funzionali, in cui è molto semplice aggiungere una nuova operazione (basta scrivere una funzione che si occupa di tutti i casi), ma è difficile aggiungere una nuova variante (poiché è necessario aggiungere una nuova caso per tutte le tue funzioni).


1
Buona risposta! Una parte con cui non sono d'accordo: la distinzione che stai facendo sull'incapsulamento non è valida. Incapsulamento significa sempre "vietare l'accesso oltre questa interfaccia" - questo vale sia per le impostazioni OOP che per quelle non OOP. Quindi questa parte non è davvero qualcosa di unico per OOP.
DW

@DW Ho provato a chiarire questo, dicendo che non è unico per OOP ma che è la differenza tra incapsulamento e astrazione. Grazie per il feedback!
jmite,

2
OK. Ma ho ancora una visione diversa di ciò che è scritto qui sull'argomento. Hai scritto che "ecco alcuni modi in cui OOP è più sfumato di quello che hai detto", ma l'incapsulamento non è un modo in cui OOP è più sfumato di quanto è stato scritto nella domanda. L'incapsulamento è quello che è, in qualsiasi paradigma. E dove hai scritto che "Quello che stai descrivendo non è OOP, è astrazione", ho pensato che la domanda originale stesse cercando di descrivere l'incapsulamento (non solo l'astrazione). Immagino che lascerò questo commento come una prospettiva diversa. Penso che la risposta sia molto utile!
DW

L'ereditarietà è una caratteristica comune, ma mancano molte lingue OO importanti.
Bradd Szonye,

Buona risposta, ma IMO stai esagerando l'esempio dell'auto. Un motore per un determinato modello ha un'interfaccia ben definita (albero a camme, "prese" della staffa di montaggio, ecc.). È possibile sostituire un semplice carburatore vecchio con uno a iniezione, aggiungere un turbocompressore, ecc. Senza influire sulla trasmissione. (Sebbene un motore diesel richieda un serbatoio del carburante modificato IIRC.) Al contrario, è possibile sostituire un cambio manuale con un automatico e AFAIK che non influisce affatto sul motore.
David

11

Abbiamo davvero bisogno delle lingue OO per gestire la complessità del software?

Questo dipende dal significato della parola "necessità".

Se "bisogno" significa che richiede, no non lo richiediamo.

Se "bisogno" significa "fornisce forti benefici", allora direi "Sì", lo desideriamo.

Quadro generale

Le lingue OO associano la funzionalità ai dati.

È possibile evitare questa associazione e scrivere funzioni che passano intorno ai valori dei dati.

Ma poi probabilmente finirai con costellazioni di dati che vanno insieme e inizierai a passare intorno a tuple, record o dizionari di dati.

E davvero, questo è tutto ciò che le chiamate di metodo sono: funzioni parziali su insiemi di dati associati.

Caratteristica per caratteristica

Caratteristiche di OOP:

  • L'ereditarietà consente il riutilizzo del codice (mixin) e del concetto (Classi / interfacce di base astratte), ma è possibile ottenerlo ridecorando le funzioni e le variabili in un ambito secondario.
  • L'incapsulamento consente di nascondere le informazioni in modo che possiamo lavorare a livelli più alti di astrazione, ma puoi farlo con file di intestazione, funzioni e moduli.
  • Il polimorfismo ci consente di usare argomenti di tipo diverso purché tali argomenti supportino le stesse interfacce, ma possiamo farlo anche con funzioni.

Tuttavia, nessuna di queste cose accade così facilmente come con un linguaggio orientato agli oggetti con supporto di prima classe di tali funzionalità.

Riferimenti

Ci sono molti critici di OOP .

Tuttavia, gli studi sembrano indicare che otteniamo una maggiore produttività del programmatore dal riutilizzo del codice tramite OOP. Questa è una scoperta controversa e alcuni ricercatori affermano di non poter riprodurre questi incrementi di produttività, dati alcuni vincoli. (fonte)

Conclusione

Non "abbiamo bisogno" di OOP. Ma in alcuni casi l'utente vuole OOP.

La mia comprensione è che i programmatori maturi possono essere piuttosto produttivi nello stile orientato agli oggetti. E quando i pacchetti hanno oggetti core con interfacce semplici che sono facilmente comprensibili, anche i nuovi programmatori possono diventare abbastanza rapidamente produttivi.


10

Proverò ad essere breve.

Il principio fondamentale di OO è la combinazione di dati e comportamento in una singola unità organizzativa (un oggetto).

Questo è ciò che ci consente di controllare la complessità ed è stato un concetto piuttosto innovativo quando è emerso. Confrontalo con i file da un lato (dati puri), i programmi che leggono ed elaborano quei file dall'altro (logica pura) e l'output (di nuovo dati puri).

Solo una volta che hai quel pacchetto di dati e logica insieme, modellando alcune entità del mondo reale, puoi iniziare a scambiare messaggi, creare classi secondarie, separare dati e comportamenti privati ​​da dati pubblici, implementare comportamenti polimorfici, fare tutto questo magico specifico per OO.

Quindi sì, OO è un grosso problema. E no, non è solo un mucchio di vecchie cose con un nome di fantasia.

Smontare tutto, guardare gli elementi e poi dire "oh, beh, non c'è niente qui che non ho mai visto prima" non sta riconoscendo l'assemblaggio che contiene l'innovazione. Il risultato è più della somma delle sue parti.


8

Non esiste una definizione "ufficiale" di programmazione orientata agli oggetti e le persone ragionevoli non sono d'accordo su ciò che sta effettivamente definendo la qualità di OO. Alcuni dicono che i messaggi, alcuni dicono i sottotipi, alcuni dicono l'eredità, altri dicono il raggruppamento di dati e comportamento. Ciò non significa che il termine non abbia senso, ma solo che non dovresti essere troppo preso dai litigi su ciò che è reale OO.

L'incapsulamento e la modularità sono principi fondamentali del design e dovrebbero essere applicati in tutti i paradigmi di programmazione. I sostenitori di OO non sostengono che queste proprietà possono essere raggiunte solo con OO - solo che OO è particolarmente adatto a raggiungere questo obiettivo. Naturalmente i sostenitori di altri paradigmi come la programmazione funzionale rivendicano lo stesso per il loro paradigma. In pratica molti linguaggi di successo sono multi-paradigma e l'OO, funzionale ecc. Dovrebbero essere visti come strumenti piuttosto che "l'unica vera via".

Penso che tutti i principi utilizzati per gestire la complessità possano essere realizzati con linguaggi di programmazione procedurali.

È vero, perché alla fine puoi fare qualsiasi cosa in qualsiasi linguaggio di programmazione. Potrebbe essere più semplice in alcune lingue che in altre, poiché tutte le lingue hanno diversi punti di forza e di debolezza.


7

Qualcosa che le altre risposte non hanno menzionato: state.

Parli di OO come strumento per gestire la complessità . Qual è la complessità? È un termine confuso. Tutti abbiamo questo senso gestalt di ciò che significa, ma è più difficile fissarlo. Potremmo misurare la complessità ciclomatica, ovvero il numero di percorsi di runtime attraverso il codice, ma non so di cosa stiamo parlando quando utilizziamo OO per gestire la complessità.

Ciò di cui penso stiamo parlando è la complessità legata allo stato.

Ci sono due idee principali dietro l' incapsulamento . Uno di questi, il nascondimento dei dettagli di implementazione , è piuttosto ben coperto nelle altre risposte. Ma un altro sta nascondendo il suo stato di runtime . Non ci occupiamo dei dati interni degli oggetti; passiamo messaggi (o chiamiamo metodi se preferite i dettagli dell'implementazione rispetto al concetto, come sottolineato da Jörg Mittag). Perché?

Le persone hanno già detto che è perché non puoi cambiare la struttura interna dei tuoi dati senza cambiare il codice a cui accedono e vuoi farlo in un posto (il metodo di accesso) invece di 300 posti.

Ma è anche perché rende il codice difficile da ragionare su : il codice procedurale (sia in un linguaggio che è di natura procedurale o semplicemente scritto in quello stile) offre poco aiuto per imporre restrizioni alla mutazione dello stato. Tutto può cambiare in qualsiasi momento e ovunque. La chiamata di funzioni / metodi può avere un'azione spettrale a distanza. I test automatizzati sono più difficili, poiché il successo dei test è determinato dal valore di variabili non locali ampiamente accessibili / accessibili.

Gli altri due grandi paradigmi di programmazione (OO e funzionali) offrono soluzioni interessanti, ma quasi diametralmente opposte al problema della complessità legata allo stato. Nella programmazione funzionale si cerca di evitarlo del tutto: le funzioni sono generalmente pure, le operazioni sulle strutture dati restituiscono copie anziché aggiornare l'originale in atto, ecc.

OO d'altra parte offre strumenti per gestire lo stato (invece di strumenti per evitarlo). Oltre agli strumenti a livello di lingua come modificatori di accesso (protetti / pubblici / privati), getter e setter, ecc. Ci sono anche una serie di convenzioni correlate come la Legge di Demetra che sconsiglia di raggiungere attraverso gli oggetti per ottenere dati su altri oggetti .

Nota che non hai bisogno di oggetti per fare veramente tutto questo: potresti avere una chiusura che ha dati inaccessibili e restituisce una struttura di dati di funzioni per manipolarlo. Ma non è un oggetto? Non si adatta alla nostra concezione di cosa sia un oggetto, intuitivamente? E se abbiamo questo concetto, non è meglio riprogrammarlo nel linguaggio piuttosto che (come hanno detto altre risposte) basandosi su un'esplosione combinatoria di implementazioni ad hoc concorrenti?


5

Abbiamo davvero bisogno delle lingue OO per gestire la complessità del software?

No. Ma possono aiutare in molte situazioni.

Ho usato principalmente un singolo linguaggio OO per decenni, ma la maggior parte del mio codice è in realtà strettamente procedurale in stile pre-OO. Tuttavia, per qualsiasi cosa che coinvolga una GUI, utilizzo la vasta libreria OO del linguaggio di metodi e oggetti incorporati, perché semplifica enormemente il mio codice.

Ad esempio, un'applicazione Windows che utilizza l'API Windows originale di basso livello per visualizzare un modulo, un pulsante e un campo di modifica richiede molto codice, mentre invece le librerie di oggetti fornite con Visual Basic o C # o Delphi fanno lo stesso programma minuscolo e banale. Quindi, il mio codice OO è di solito relativamente piccolo e per la GUI, mentre il mio codice che quegli oggetti invocano è in genere molto più grande e di solito non si preoccupa di essere OO (anche se può variare a seconda del problema che sto cercando di risolvere).

Ho visto programmi OO che erano eccessivamente complicati, si basavano su complicate regole esoteriche su come gli oggetti venivano implementati e avrebbero potuto essere molto più semplici se scritti senza concetti OO. Ho anche visto il contrario: sistemi complessi che chiedono di essere reimplementati e semplificati usando oggetti.

Man mano che acquisisci esperienza, scoprirai che situazioni diverse richiedono strumenti e soluzioni diversi e una dimensione non va bene per tutti.


3

Come qualcuno che è coinvolto in un grande progetto interamente scritto in C, posso sicuramente dire che la risposta è un chiaro "no".

La modularità è importante. Ma la modularità può essere implementata praticamente in qualsiasi linguaggio decente. Ad esempio, C supporta la compilazione modulare, i file di intestazione e i tipi di struttura. Questo è sufficiente per il 99% dei casi. Definire un modulo per ogni nuovo tipo di dati astratto necessario e definire le funzioni per operare sul tipo di dati. A volte, vuoi prestazioni e quelle funzioni sono nel file di intestazione come funzioni incorporate, altre volte utilizzerai funzioni standard. È tutto invisibile per l'utente in che modo viene scelto.

Composizione supporto strutture. Ad esempio, puoi avere una tabella hash bloccata che consiste in un blocco mutex e una tabella hash normale. Questa non è una programmazione orientata agli oggetti; non viene eseguita alcuna sottoclasse. La composizione è uno strumento molto più antico dell'idea di programmazione orientata agli oggetti.

Per l'1% dei casi in cui la modularità a livello di compilazione non è sufficiente e è necessaria la modularità di runtime, esiste una cosa chiamata puntatori di funzione. Consentono di avere implementazioni individuali di un'interfaccia ben definita. Si noti che questa non è una programmazione orientata agli oggetti in un linguaggio non orientato agli oggetti. Questo sta definendo un'interfaccia e quindi implementandola. Ad esempio, la sottoclasse non viene utilizzata qui.

Considera forse il progetto open source più complesso che esista. Vale a dire, il kernel Linux. È scritto interamente in linguaggio C. Viene eseguito principalmente utilizzando gli strumenti standard di modularità a livello di compilazione, compresa la composizione, e occasionalmente ogni volta che è necessaria la modularità di runtime, i puntatori a funzione vengono utilizzati per definire e implementare un'interfaccia.

Se si tenta di trovare un esempio di programmazione orientata agli oggetti nel kernel Linux, sono sicuro che trovare tale esempio sia molto difficile, a meno che non si estenda la programmazione orientata agli oggetti per includere tali attività standard come "definire un'interfaccia e quindi implementarla".

Nota che anche il linguaggio di programmazione C supporta la programmazione orientata agli oggetti se ne hai davvero bisogno. Ad esempio, si consideri il toolkit grafico dell'interfaccia utente GTK. In realtà è orientato agli oggetti, sebbene scritto in un linguaggio non orientato agli oggetti. Quindi, questo dimostra che l'idea che hai bisogno di un "linguaggio orientato agli oggetti" è profondamente imperfetta. Non c'è nulla che una lingua orientata agli oggetti possa fare che un altro tipo di lingua non possa fare. Inoltre, se sei un programmatore esperto, sai come scrivere codice orientato agli oggetti in qualsiasi lingua molto facilmente. Ad esempio, non è un onere usare C.

Quindi, le conclusioni sono che i linguaggi orientati agli oggetti sono probabilmente utili solo per i programmatori principianti che non riescono a capire come il concetto sia effettivamente implementato. Tuttavia, non vorrei essere vicino a nessun progetto in cui i programmatori sono programmatori così inesperti.


1
"[...] le conclusioni sono che i linguaggi orientati agli oggetti sono probabilmente utili solo per i programmatori principianti che non riescono a capire come il concetto è effettivamente implementato." Interessante. Quali lingue hai in mente? Hai esempi di progetti open source scritti in queste lingue che hanno fallito o non sono falliti?
Vincent Savard,

3
Sollevi alcuni punti positivi, ma la tua idea principale è imperfetta. Sì, è possibile implementare concetti OO come incapsulamento, invio virtuale, ereditarietà e persino raccolta dei rifiuti in un linguaggio come C. È anche possibile farlo in assembly. Non semplifica la programmazione. Programmare e soprattutto progettare in un linguaggio come C è sicuramente più difficile di quanto non lo sia in un linguaggio OO. In C è necessario mappare i concetti alla loro implementazione, in un linguaggio OO non è necessario eseguire tale passaggio (almeno non per i concetti OO).
fishinear del

1
"[puntatori a funzione] consentono di avere implementazioni individuali di un'interfaccia ben definita. Si noti che questa non è una programmazione orientata agli oggetti in un linguaggio non orientato agli oggetti. Si tratta di definire un'interfaccia e quindi di implementarla." Siamo spiacenti, ma è completamente sbagliato, perché questo è esattamente ciò che è OOP. "Ad esempio, la sottoclasse non viene utilizzata qui" La sottoclasse non è una funzione obbligatoria di OOP. Si noti, ad esempio, che JavaScript è un linguaggio orientato agli oggetti che non include la sottoclasse (o, per questo, le classi ... Solo oggetti che contengono riferimenti a funzioni).
Jules,

1
Per chiarire il mio ultimo commento, il mio punto è che il principale fattore di distinzione tra OOP (non necessariamente un linguaggio OO specifico) e altri metodi è che in OOP definiamo interfacce che operano in modo astratto sui dati senza bisogno di conoscere il formato di tali dati tramite vincolando l'implementazione delle interfacce ai dati stessi. Questo è OOP. Il metodo di implementazione è irrilevante, che si tratti di una classe di stile Java, un oggetto JavaScript (in effetti una mappa di nomi da attribuire, che può essere dati o codice) o una struttura contenente puntatori a funzione e un vuoto * per i dati.
Jules,

1
"Quindi, le conclusioni sono che i linguaggi orientati agli oggetti sono probabilmente utili solo per i programmatori principianti che non riescono a capire come il concetto è effettivamente implementato." .... E questo, francamente, è chiaramente un insulto. Conosco abbastanza bene come vengono implementati questi concetti. Ho fatto abbastanza lavoro usando anche per essere competente, anche. In passato ho persino implementato sia un interprete che un compilatore per le lingue OO. Ma poiché preferisco lavorare in linguaggi di livello superiore con oggetti di prima classe, devo essere un programmatore principiante con il quale preferiresti non lavorare ?!
Jules,

2

La ragione per introdurre paradigmi di programmazione, inclusi metodi orientati agli oggetti, è rendere più semplice la realizzazione di programmi più sofisticati e potenti. Nel numero di agosto 1981 di Byte Magazine, Daniel Ingalls , uno dei principali creatori di Smalltalk, ha definito "orientato agli oggetti" come coinvolge le seguenti capacità:

  • gestione automatica dell'archiviazione
  • capacità di scambiare messaggi
  • una metafora uniforme che si applica a tutte le operazioni della lingua
  • nessun componente dipende dall'interno di un altro componente (modularità)
  • il programma definisce solo il comportamento degli oggetti, non la loro rappresentazione (polimorfismo)
  • ogni componente dovrebbe apparire in un solo posto (factoring)
  • l'uso di una macchina virtuale indipendente dall'hardware
  • ogni componente accessibile all'utente dovrebbe essere disponibile per l'osservazione e il controllo (principio reattivo)
  • non ci dovrebbe essere un controller globale (nessun sistema operativo)

Questi erano i principi che Ingalls ha identificato come considerazioni di progettazione guida per SmallTalk-80 sviluppato da Xerox Parc Research. Nel suddetto articolo di rivista è possibile leggere una descrizione dettagliata di ciascuno di questi principi e di come essi contribuiscono al paradigma orientato agli oggetti secondo Ingalls.

Tutti questi principi possono essere applicati usando qualsiasi linguaggio completo di Turing, sia esso procedurale, linguaggio assembleare o altro. Questi sono principi di progettazione, non una specifica del linguaggio. Un linguaggio orientato agli oggetti ha lo scopo di semplificare l'utilizzo di questi principi durante la creazione di software.

Ad esempio, per prendere il primo dei principi di Ingall (gestione automatica dell'archiviazione), chiunque può scrivere il proprio sistema di gestione automatica dell'archiviazione in un linguaggio procedurale, ma sarebbe molto difficile farlo. Quando si utilizza un linguaggio come SmallTalk o Java in cui è integrata la gestione automatica della memoria, il programmatore non deve fare altrettanto lavoro per la gestione della memoria. Il compromesso è che il programmatore ottiene meno controllo sul modo in cui viene utilizzata la memoria. Quindi, c'è un vantaggio e uno svantaggio. L'idea di un paradigma progettuale come la programmazione orientata agli oggetti è che i benefici del paradigma supereranno gli svantaggi di almeno alcuni programmatori.


Penso che si applichino le stesse regole nel caso delle lingue specifiche del dominio. Stessi vantaggi e svantaggi ... L'unica differenza è che i DSL possono essere resi abbastanza semplici da consentire agli utenti finali di lavorare, poiché il "linguaggio" corrisponde alla loro comprensione dello spazio del problema e nient'altro è incluso.

0

Un modo di gestire la complessità del software è di separare il framework dalle azioni desiderate utilizzando interamente un linguaggio specifico di dominio . Ciò significa che il livello del codice di programmazione è distinto dal livello al quale sono configurati i risultati desiderati - un linguaggio o un sistema completamente diverso. Quando questo viene fatto correttamente, il codice convenzionale diventa essenzialmente una libreria e l'utente o l'altra persona che crea i risultati desiderati collega le cose con un linguaggio di scripting o uno strumento di progettazione visiva, come un generatore di report.

Per funzionare, ciò richiede di tracciare un confine rigoroso attorno a quali operazioni saranno possibili e al modo in cui si collegano (linguaggio di script o design visivo, come uno strumento di costruzione di moduli). I metadati sono un modo importante per sottrarre la configurazione di runtime dai dettagli di codifica, consentendo a un sistema di supportare un'ampia gamma di risultati desiderati. Se i confini sono definiti e rispettati (non accettando ogni richiesta di estensione che si presenta) puoi avere un sistema duraturo e robusto che funziona per le persone, senza che debbano essere programmatori per realizzare ciò che vogliono.

Martin Fowler ha scritto un libro su questo e la tecnica è vecchia quasi quanto la programmazione stessa. Si potrebbe quasi dire che tutti i linguaggi di programmazione sono linguaggi specifici del dominio e quindi l'idea è endemica, trascurata perché è così ovvia. Puoi comunque creare i tuoi strumenti di scripting o visual design per semplificarti la vita. A volte generalizzare un problema rende molto più facile la risoluzione!


0

Questa è un'ottima domanda e sento che le risposte fornite qui non hanno reso giustizia, quindi andrò avanti e aggiungerò i miei pensieri.

L'obiettivo è: gestire la complessità del software . L'obiettivo non è "utilizzare il linguaggio OO".

Non c'è alcuna "ragione" dietro l'introduzione di un nuovo paradigma. È qualcosa che è accaduto naturalmente quando la codifica è diventata più matura. È più sensato scrivere un codice in cui aggiungere un pullman alla fine del treno (il treno viene modellato utilizzando un elenco collegato) anziché aggiungere un nuovo nodo alla fine dell'elenco collegato.


Codifica in termini di entità del mondo reale è semplicemente il modo più ovvio e corretto di codice quando ci troviamo di codifica per le entità del mondo reale.


Un computer può lavorare con l'aggiunta di un nodo alla fine dell'elenco collegato con la stessa facilità con cui può aggiungere l'aggiunta di un pullman aggiuntivo alla fine del treno. Ma per gli esseri umani è più facile lavorare con il treno e l'allenatore che con la lista e i nodi collegati anche se quando si scende di livello, troviamo che il treno viene modellato mediante una lista collegata.

La protezione o la crittografia dei file non può ottenere l'incapsulamento. L'opposto della crittografia è la decrittografia. L'opposto dell'incapsulamento è la decapsulazione che significa decomposizione di strutture e classi nei linguaggi di programmazione per ottenere prestazioni migliori. Le prestazioni ottenute riducendo il traffico di memoria ed evitando i controlli delle regole OOP.

Quindi puoi scrivere codice sia crittografato che ben incapsulato perché questi due sono concetti diversi.

L'incapsulamento aiuta a gestire la complessità in quanto vicina alla realtà.

Pertanto, programma negli oggetti perché, è più facile per te programmare ed è più veloce per te e per tutti gli altri capire.


0

L'unica cosa da ricordare è questa:
OOP non riguarda le funzionalità del linguaggio; riguarda il modo in cui strutturi il tuo codice .

OOP è un modo di pensare e di progettare l'architettura del tuo codice e può essere fatto in quasi tutte le lingue. Ciò include in particolare quei linguaggi di basso livello, non OO, che si chiamano assembler e C. Si può fare una programmazione perfettamente orientata agli oggetti in assembler, e il kernel Linux, che è scritto in C, è abbastanza orientato agli oggetti in molti aspetti .

Detto questo, le funzionalità OO in una lingua riducono notevolmente la quantità di codice della piastra di caldaia che è necessario scrivere per ottenere i risultati desiderati . Laddove è necessario definire esplicitamente una tabella di funzione virtuale e riempirla con i puntatori di funzione appropriati in C, non si fa nulla in Java e il gioco è fatto. I linguaggi OO rimuovono semplicemente tutto ciò che consente l'innesto dal codice sorgente, nascondendolo dietro simpatiche astrazioni a livello di linguaggio (come classi, metodi, membri, classi di base, chiamate implicite di costruttore / distruttore, ecc.).

Quindi, no, non abbiamo bisogno delle lingue OO per fare OOP. È solo che OOP è molto più facile da fare con un linguaggio OO decente.


-1

La programmazione orientata agli oggetti è molto più di semplici moduli + incapsulamento. Come dici tu, è possibile usare moduli + incapsulamento in un linguaggio (procedurale) non orientato agli oggetti. OOP coinvolge molto di più: coinvolge oggetti e metodi. Quindi no, questo non cattura OOP. Vedi, ad esempio, https://en.wikipedia.org/wiki/Object-oriented_programming o una buona introduzione di un libro di testo a OOP.


Grazie per la risposta. Potresti consigliarne uno?
Scambia il cambio di

-2

Il motivo principale è che, man mano che un programma diventa più complesso, è necessario renderne invisibili alcune parti da altre parti, oppure la complessità dell'app e il numero di funzioni faranno sgocciolare il cervello dalle orecchie.

Immaginiamo un sistema di 100 classi, ognuna con circa 20 operazioni che possono essere eseguite su di esse; sono 2.000 funzioni. Tuttavia, di questi, forse solo 500 sono operazioni complete come 'Salva' ed 'Elimina', mentre 1500 sono funzioni interne che svolgono un po 'di manutenzione o hanno un ruolo di utilità. Tener conto di;

// intentionally in a non-specific language!

setName(person, name) {
    nameParts = splitPersonName(name);
    person.firstName = nameParts[0];
    person.lastName = nameParts[1];
    person.modified = true;
}

splitPersonName(name) {
    var result = [];
    result.add(name.substring(0, name.indexOf(" ")));
    result.add(name.substring(name.indexOf(" ") + 1));
    return result;
}

Quindi SetNameè una funzione che le persone dovrebbero fare a una persona, ma SplitPersonNameè una funzione di utilità utilizzata dalla persona.

La semplice programmazione procedurale non fa distinzione tra queste due operazioni. Ciò significa che i tuoi 2.000 funzionali sono tutti alla ricerca della tua attenzione. Tuttavia, se potessimo contrassegnare queste funzioni come "disponibili a tutti coloro che hanno un record personale" e "utilizzate solo come funzione di utilità all'interno del record personale", la nostra attenzione è ora 500 funzioni "disponibili a tutti" e 15 "utilità" funzioni per la classe che stai modificando.

Questo è cosa publice privatefare;

public class Person {
    public void setName(...) {...}
    private string[] splitPersonName(...) { ...}
}

1
Non sono sicuro che tu abbia capito correttamente la mia domanda. Sono già a conoscenza dell'incapsulamento e del nascondere i dati come un modo per gestire la complessità. Penso solo che ciò possa essere facilmente realizzato anche nei linguaggi procedurali, dividendo il programma in moduli che svolgono compiti semplici ben definiti i cui meccanismi interni sono specificati in fonti protette separate. Allora perché OOP quando possiamo fare queste cose in linguaggi procedurali? Questa è la mia domanda
Scambiocambia

2
Immagino che la mia risposta sia che se vuoi fare questo genere di cose, dovrai scrivere strumenti speciali e costrutti di linguaggio per farlo (ad esempio, una speciale chiamata 'include' a un file include che potrebbe non essere incluso altrove). Una volta che hai iniziato quel percorso, hai effettivamente iniziato a implementare un linguaggio orientato agli oggetti a modo tuo. Ad esempio, C ++ era originariamente un preprocessore che produceva un C semplice , e sospetto che una volta implementato il sistema assomigli molto a C ++ sopra C.
user62575

3
@steakexchange Nota che OOP è stato sviluppato in un momento in cui molti linguaggi procedurali non avevano moduli del genere. Alcuni non chiamerebbero nemmeno tali lingue procedurali. In effetti, non c'è nulla che dica che un linguaggio procedurale non deve essere OO o viceversa. Fai attenzione alle etichette: possono facilmente fuorviarti. Se il tuo linguaggio procedurale supporta moduli che hanno campi e procedure pubblici e privati, è un bene per te :) La differenza principale tra "procedurale tradizionale" e "OOP" è che l'invio di chiamate è più flessibile in OOP - anzi, in OOP rigoroso, tu mai sapere quale codice chiami.
Luaan,

2
@steakexchange Nelle lingue della famiglia ML, i moduli funzionano alla grande, e in combinazione con lambdas, ti danno tutta la potenza di qualsiasi linguaggio OO (dopotutto, una funzione è un'interfaccia con un singolo metodo - non è che quasi ciò che è raccomandato da "buon codice" ragazzi in OO?: P). Per vari motivi, sono ancora meno utilizzati rispetto ai linguaggi più procedurali come C ++ o Java, ma hanno il loro fascino e molte persone stanno cercando di educare le persone su come possono semplificare la loro vita (con più o meno successo).
Luaan,

C ha effettivamente queste cose. Ha moduli (file .c) con interfacce (file .h) e può avere metodi (funzioni) pubblici (extern) e non pubblici (extern). Puoi persino avere il polimorfismo del povero uomo con matrici di indicatori di funzione, non sto dicendo che OO sia facile in C (o forse, sano) ma l'incapsulamento è abbastanza facile,
Nick Keighley
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.