it-swarm.it

Perché OOP è difficile?

Quando ho iniziato a utilizzare un linguaggio orientato agli oggetti (Java), praticamente sono diventato "cool" e ho iniziato a scrivere codice. Non ci ho mai pensato fino a poco tempo fa dopo aver letto molte domande su OOP. L'impressione generale che ottengo è che le persone lottano con esso. Dal momento che non l'ho considerato difficile e non direi che sono un genio, sto pensando che avrei dovuto perdere qualcosa o averlo frainteso.

Perché OOP è difficile da capire? Is è difficile da capire?

93
gablin

Personalmente ho trovato la meccanica di OOP abbastanza facile da capire. La parte difficile per me era il "perché" di esso. Quando sono stato esposto per la prima volta, sembrava una soluzione alla ricerca di un problema. Ecco alcuni motivi per cui penso che molte persone lo trovino difficile:

  1. L'insegnamento IMHO OO dall'inizio è un'idea terribile. La codifica procedurale non è una "cattiva abitudine" ed è lo strumento giusto per alcuni lavori. I metodi individuali in un programma OO tendono comunque ad essere piuttosto procedurali. Inoltre, prima di apprendere la programmazione procedurale abbastanza bene da rendere visibili i suoi limiti, OO non sembra molto utile allo studente.

  2. Prima di poter veramente afferrare OO, è necessario conoscere le basi delle strutture dati e le funzioni di associazione tardiva/ordine superiore. È difficile stimolare il polimorfismo (che in sostanza passa attorno a un puntatore ai dati e a un mucchio di funzioni che operano sui dati) se non capisci nemmeno i concetti di strutturare i dati invece di usare solo le primitive e passare attorno a funzioni di ordine superiore/puntatori a funzioni.

  3. I modelli di progettazione dovrebbero essere insegnati come qualcosa di fondamentale per OO, non come qualcosa di più avanzato. I modelli di progettazione ti aiutano a vedere la foresta attraverso gli alberi e forniscono esempi relativamente concreti di dove OO può semplificare problemi reali e vorrai comunque impararli alla fine. Inoltre, una volta ottenuto OO, la maggior parte dei modelli di progettazione diventa evidente con il senno di poi.

120
dsimcha

Penso che ci siano alcuni fattori che non sono ancora stati menzionati.

Prima di tutto, almeno in "OOP puro" (ad es. Smalltalk) dove tutto è un oggetto, devi distorcere la tua mente in una configurazione piuttosto innaturale per pensare a un numero (solo per un esempio ) come oggetto intelligente anziché solo un valore, poiché in realtà, 21 (ad esempio) davvero è solo un valore. Ciò diventa particolarmente problematico quando da un lato ti viene detto che un grande vantaggio di OOP sta modellando la realtà più da vicino, ma inizi prendendo ciò che assomiglia moltissimo a una visione ispirata all'LSD anche delle parti più elementari e ovvie della realtà.

In secondo luogo, l'ereditarietà in OOP non segue neanche da vicino i modelli mentali della maggior parte delle persone. Per la maggior parte delle persone, classificare le cose in modo più specifico no ha un punto vicino alle regole assolute necessario per creare una gerarchia di classi che funzioni. In particolare, creando un class D che eredita da un altro class B indica che gli oggetti di class D condividi in modo assolutamente positivo tutto le caratteristiche di class B. class D può aggiungere nuove e diverse caratteristiche proprie, ma tutte le caratteristiche di class B deve rimanere intatto.

Al contrario, quando le persone classificano le cose mentalmente, in genere seguono un modello molto più flessibile. Ad esempio, se una persona stabilisce alcune regole su ciò che costituisce una classe di oggetti, è abbastanza tipico che quasi ogni regola possa essere infranta fintanto che ne seguono abbastanza altre. Anche le poche regole che non si possono veramente infrangere possono quasi sempre essere "allungate" un po 'comunque.

Solo per esempio, considera "auto" come una classe. È abbastanza facile vedere che la maggioranza vasta di ciò che la maggior parte della gente considera "auto" ha quattro ruote. La maggior parte delle persone, tuttavia, ha visto (almeno una foto di) un'auto con solo tre ruote. Alcuni di noi dell'età giusta ricordano anche una o due macchine da corsa dei primi anni '80 (circa) con sei ruote - e così via. Questo ci lascia sostanzialmente con tre scelte:

  1. Non affermare nulla sul numero di ruote di un'auto, ma ciò tende a supporre implicitamente che sarà sempre 4 e che il codice potrebbe rompersi per un altro numero.
  2. Afferma che tutte le auto hanno quattro ruote e classifica quelle altre come "non auto", anche se sappiamo che lo sono davvero.
  3. Progetta la classe per consentire la variazione del numero di ruote, per ogni evenienza, anche se ci sono buone possibilità che questa capacità non sarà mai necessaria, utilizzata o testata correttamente.

Insegnare a OOP spesso si concentra sulla costruzione di enormi tassonomie - ad esempio, frammenti di quella che sarebbe una gigantesca gerarchia di tutta la vita conosciuta sulla terra, o qualcosa su quell'ordine. Ciò solleva due problemi: in primo luogo, tende a condurre molte persone a concentrarsi su enormi quantità di informazioni che sono assolutamente irrilevanti per la domanda in corso. Ad un certo punto ho visto una discussione piuttosto lunga su come modellare le razze di cani e se (per esempio) " barboncino in miniatura "dovrebbe ereditare da" barboncino a grandezza naturale ", o viceversa, o se ci dovrebbe essere una classe" Barboncino "di base astratta, con" barboncino a grandezza naturale "e" barboncino in miniatura "che ereditano entrambi da ciò. ignorare era che l'applicazione doveva occuparsi di tenere traccia delle licenze per cani e ai fini a portata di mano era del tutto adeguato avere un singolo campo chiamato "razza" (o qualcosa in quell'ordine) senza modellare la relazione tra le razze a tutti.

In secondo luogo, e quasi importante, porta a concentrarsi sulle caratteristiche degli articoli, invece di concentrarsi sulle caratteristiche che sono importanti per il compito da svolgere. Porta a modellare le cose così come sono, dove (la maggior parte delle volte) ciò che è veramente necessario è costruire il modello più semplice che soddisfi le nostre esigenze e usare l'astrazione per adattarsi alle sottoclassi necessarie per astrazione che abbiamo costruito.

Infine, ripeto: stiamo lentamente seguendo lo stesso percorso intrapreso dai database nel corso degli anni. I primi database seguivano il modello gerarchico. Oltre a concentrarsi esclusivamente sui dati, questa è una singola eredità. Per un breve periodo, alcuni database hanno seguito il modello di rete, sostanzialmente identico all'ereditarietà multipla (e visti da questo punto di vista, più interfacce non sono abbastanza diverse da più classi di base da notare o preoccuparsi).

Molto tempo fa, tuttavia, i database convergevano in gran parte sul modello relazionale (e anche se non sono SQL, a questo livello di astrazione anche i database "NoSQL" attuali sono relazionali). I vantaggi del modello relazionale sono sufficientemente noti che non mi preoccuperò di ripeterli qui. Noterò solo che l'analogo più vicino al modello relazionale che abbiamo nella programmazione è la programmazione generica (e scusate, ma nonostante il nome, Java generics, per un esempio, non si qualificano davvero , sebbene siano un piccolo passo nella giusta direzione).

57
Jerry Coffin

OOP richiede la capacità di pensare in modo astratto; un dono/maledizione che poche persone, anche programmatori professionisti, hanno davvero.

26
John Kraft

Ogni paradigma richiede una certa spinta "oltre il limite" per afferrare, per la maggior parte delle persone. Per definizione, è una nuova modalità di pensiero e quindi richiede una certa quantità di lasciar andare le vecchie nozioni e una certa quantità di comprendere appieno perché le nuove nozioni sono utili.

Penso che gran parte del problema sia che i metodi utilizzati per insegnare la programmazione informatica sono piuttosto scarsi in generale. OOP è così comune ora che non è così evidente, ma lo vedi ancora spesso nella programmazione funzionale:

  • concetti importanti sono nascosti dietro nomi strani (FP: Cos'è una monade? OOP: Perché li chiamano funzioni a volte e metodi altre volte?)

  • strani concetti sono spiegati in metafora anziché in termini di ciò che effettivamente fanno, o perché li useresti, o perché qualcuno abbia mai pensato di usarli (FP: Una monade è una tuta spaziale, racchiude un po 'di codice. OOP: An l'oggetto è come un'anatra, può fare rumore, camminare ed ereditare dall'animale)

  • le cose buone variano da persona a persona, quindi non è del tutto chiaro quale sarà il punto di svolta per qualsiasi studente, e spesso l'insegnante non riesce nemmeno a ricordare. (FP: Oh, le monadi ti permettono di nascondere qualcosa nel tipo stesso e portarlo avanti senza dover scrivere esplicitamente ciò che sta accadendo ogni volta. OOP: Oh, gli oggetti ti consentono di mantenere le funzioni per un tipo di dati con quei dati.)

La cosa peggiore è che, come indica la domanda, alcune persone si affretteranno immediatamente a capire perché il concetto è buono e altri no. Dipende davvero da quale sia il punto critico. Per me, capire che gli oggetti archiviano dati e metodi per tali dati è stata la chiave, dopo che tutto il resto si adattava semplicemente come estensione naturale. Poi ho fatto salti successivi come rendermi conto che una chiamata di metodo da un oggetto è molto simile a quella di effettuare una chiamata statica con quell'oggetto come primo parametro.

I piccoli salti successivi aiutano a perfezionare la comprensione, ma è quello iniziale che prende una persona da "OOP non ha senso, perché le persone fanno questo?" a "OOP è il migliore, perché le persone fanno qualcos'altro?"

21
CodexArcanum

Penso che puoi riassumere la difficoltà di base in questo modo:

// The way most people think.
Operation - object - parameters
// Example:
Turn the car left.

// The way OOP works conceptually
Object - operation - parameters
// Example:
Car.Turn(270);

Certo, le persone possono abituarsi alla mappatura di "sinistra" come 270, e sì, dire "Car.Turn" invece di "girare la macchina" non è un grande salto. MA, per gestire bene questi oggetti e crearli, devi invertire il modo in cui pensi normalmente.

Invece di manipolare un oggetto, stiamo dicendo all'oggetto di fare effettivamente le cose da solo. Potrebbe non sembrare più difficile, ma dire a una finestra di aprirsi sembra strano. Le persone non abituate a questo modo di pensare devono lottare con quella stranezza ancora e ancora fino a quando alla fine diventa in qualche modo naturale.

21
John Fisher

Perché la spiegazione di base di OOP ha molto, molto poco a che fare con il modo in cui viene usata sul campo. La maggior parte dei programmi per insegnarla cerca di usare un modello fisico, come "Pensa a un'auto come un oggetto e le ruote come oggetti, e le porte e la trasmissione ... ", ma al di fuori di alcuni casi oscuri di programmazione di simulazione, gli oggetti sono molto più spesso usati per rappresentare concetti non fisici o per introdurre il riferimento indiretto. L'effetto è che fa capire alle persone intuitivamente nel modo sbagliato.

Insegnare dai modelli di progettazione è un modo molto migliore per descrivere OOP, in quanto mostra ai programmatori come alcuni problemi di modellazione reali possono essere effettivamente attaccati con oggetti, piuttosto che descriverli in astratto.

15
Dan Monego

Non sono d'accordo con la risposta di dsimcha per la maggior parte:

  1. Insegnare OO dall'inizio non è in realtà una cattiva idea in sé, né è insegnare linguaggi procedurali. L'importante è che insegniamo alle persone a scrivere un codice chiaro, conciso e coerente, indipendentemente da OO o procedurale.

  2. Metodi individuali in buono OO NON tendono a essere affatto procedurali. Ciò sta diventando sempre più vero con l'evoluzione dei linguaggi OO (leggi C # perché diverso da C++ è l'unico altro OO linguaggio che conosco) e la loro sintassi che sta diventando sempre più complessa di giorno in giorno (lambda, LINQ con oggetti, ecc.). L'unica somiglianza tra OO i metodi e le procedure nei linguaggi procedurali sono la natura lineare di ciascuno, che dubito cambierebbe presto.

  3. Non è possibile padroneggiare un linguaggio procedurale senza comprendere le strutture dei dati. Il concetto di puntatore è importante tanto per i linguaggi procedurali quanto per OO linguaggi. Passare i parametri per riferimento, ad esempio, che è abbastanza comune nei linguaggi procedurali, richiede di comprendere i puntatori tanto quanto è necessario per impara qualsiasi OO lingua.

  4. Non penso che i modelli di progettazione debbano essere insegnati all'inizio della programmazione OO affatto, perché non sono fondamentali per la programmazione OO affatto. Si può sicuramente essere un buon programmatore OO senza sapere nulla sui modelli di progettazione. In effetti una persona può persino usare modelli di progettazione noti senza nemmeno sapere che sono documentati come tali con nomi propri e che i libri sono scritto su di loro. Ciò che dovrebbe essere insegnato fondamentalmente sono principi di progettazione come Responsabilità singola, Open Close e Segregazione dell'interfaccia. Sfortunatamente, molte persone che si considerano OO in questi giorni o non hanno familiarità con questo concetto fondamentale o semplicemente scegliere di ignorarlo ed è per questo che abbiamo così tanta spazzatura OO codice là fuori. Solo dopo una comprensione approfondita di questi e altri principi dovrebbero essere introdotti modelli di progettazione.

Per rispondere alla domanda del poster originale, sì, OO è un concetto più difficile da comprendere rispetto alla programmazione procedurale. Questo perché non pensiamo in termini di proprietà e metodi degli oggetti della vita reale. Ad esempio, umano il cervello non pensa prontamente a "TurnOn" come un metodo TV, ma lo vede come una funzione dell'accensione umana della TV. Allo stesso modo, il polimorfismo è un concetto estraneo a un cervello umano che generalmente vede ogni oggetto della vita reale solo da uno " faccia ". L'eredità di nuovo non è naturale per il nostro cervello. Solo perché sono uno sviluppatore non significa che mio figlio sarebbe uno. In generale, il cervello umano deve essere addestrato per imparare OO mentre i linguaggi procedurali sono più naturali.

13

Penso che molti programmatori abbiano difficoltà a progettare e pianificare in anticipo. Anche se qualcuno fa tutto il design per te, è ancora possibile staccare da OOP. Se prendo un sacco di codice spaghetti e lo scarico in una classe, è davvero OOP? Qualcuno che non capisce OOP può ancora programmare in Java. Inoltre, non confondere la difficoltà di comprensione con non voler seguire un determinato metodo o non essere d'accordo con esso.

6
JeffO

Dovresti leggere Oggetti mai? Beh, quasi mai. (È richiesta l'iscrizione ACM) di Mordechai Ben-Ari che suggerisce che OOP è così difficile, perché non è un paradigma questo è in realtà naturale per modellare qualsiasi cosa (anche se ho delle riserve sull'articolo, perché non è chiaro quali criteri ritiene che un programma debba soddisfare per dire che è scritto sul paradigma OOP al contrario di un paradigma procedurale che utilizza un OO.)

5
Ken Bloom

La programmazione orientata agli oggetti in sé non è difficile.

La parte difficile arriva nel farlo bene. Dove mettere il taglio tra il codice in modo da poter spostare facilmente le cose nell'oggetto base comune ed estenderle in seguito? Come rendere il tuo codice utilizzabile da altri (estendi le classi, includi i proxy, ignora il metodo) senza saltare attraverso i cerchi per farlo.

Questa è la parte difficile, e se fatto bene può essere molto elegante, e se fatto male può essere molto impacciato. La mia esperienza personale è che richiede molta pratica in tutte le situazioni in cui VORREI che tu l'abbia fatto in modo diverso, al fine di farlo abbastanza bene questo tempo.

5
user1249

Avevo programmato GW-Basic e Turbo Pascal un bel po 'prima di essere introdotto a OO, quindi inizialmente HA FATTO ho fatto la mia testa.

Non ho idea se questo è ciò che accade agli altri, ma per me è stato così: il mio processo di pensiero sulla programmazione era puramente procedurale. Come in: "succedono cose del genere, poi succedono cose del genere", ecc. Ecc. Non ho mai considerato le variabili e i dati qualcosa di più che fugaci attori nel flusso del programma. La programmazione era "il flusso di azioni".

Suppongo che ciò che non è stato facile da capire (per quanto sembri così stupido), era l'idea che i dati/le variabili contano davvero , in un senso più profondo del semplice essere attori fugaci nel "flusso" del programma. O per dirlo in un altro modo: ho continuato a cercare di capirlo tramite cosa accade , piuttosto che tramite ciò che è , che è la vera chiave per afferrarlo.

4
Bobby Tables

Stavo solo guardando un video di Richard Feynman che parla di come le persone potrebbero effettivamente avere metodologie completamente diverse in testa quando pensano - intendo completamente diverse.

Quando eseguo progetti di alto livello, visualizzo gli oggetti, posso vederli, vedere le loro interfacce e vedere quali percorsi le informazioni devono percorrere.

Ho anche problemi a ricordare i dettagli e ho trovato OO essere un grande aiuto organizzativo - molto più facile da trovare funzionalità che scansionare un elenco di subroutine organizzato in modo approssimativo.

Per me OO è stato un grande vantaggio, ma se non visualizzi allo stesso modo o non esegui un'architettura di alto livello, è probabilmente inutile e fastidioso.

4
Bill K

Non credo sia difficile da capire, ma può darsi che molte delle domande dei programmatori siano nuove al concetto, provenienti da linguaggi procedurali.

Da quello che ho visto/letto molte persone (almeno nei forum) cercano un 'risultato' da OOP. Se sei un programmatore procedurale che non torna indietro e modifica estende il proprio codice, probabilmente può essere difficile comprenderne i vantaggi.

Inoltre, c'è molto male OOP là fuori, se le persone lo leggono/vedono, allora è facile capire perché potrebbero trovarlo difficile.

IMO devi aspettare fino a quando "scatta" o essere insegnato da qualcuno con una vera conoscenza, non credo che tu possa correre.

3
DBlackborough

Penso che il motivo OOP sia difficile per molti è perché gli strumenti non lo facilitano davvero.

I linguaggi informatici oggi sono un'astrazione di ciò che sta accadendo nel computer.

OOP è un modo astratto per rappresentare le astrazioni.

Quindi stiamo usando un'astrazione per costruire astrazioni con un'astrazione. Aggiungete a ciò che ciò che stiamo astraggendo di solito sono interazioni fisico/sociali molto complesse e, beh, non c'è da stupirsi.

3
ElGringoGrande

In realtà ho un blog chiamato "Lotte nella programmazione orientata agli oggetti", che è nato da alcune delle mie lotte per impararlo. Penso che sia stato particolarmente difficile da capire perché ho passato così tanto tempo a utilizzare la programmazione procedurale e ho avuto un momento difficile capire come un oggetto potesse essere rappresentato da una raccolta di attributi e comportamenti (ero abituato a semplicemente una raccolta di variabili e metodi).

Inoltre, ci sono molti concetti che orientano un oggetto linguistico - eredità, interfacce, polimorfismo, composizione, ecc. C'è davvero molto da imparare sulla teoria prima che tu possa effettivamente scrivere codice in modo efficace e in un oggetto orientato modo, mentre con la programmazione procedurale, è semplicemente una questione di capire cose come l'allocazione di memoria per le variabili e il punto di ingresso chiama ad altri metodi.

2
Tim Claason

Motivazione. È più difficile imparare qualcosa quando non vedi il perché, e anche quando non riesci a vedere cosa hai fatto e capire se l'hai fatto bene o no.

Ciò che serve sono piccoli progetti che usano OO per fare cose utili. Suggerirei di sfogliare un libro sugli schemi di progettazione e trovarne uno che è ovviamente utile e funziona bene con OO. (I ho usato la strategia una volta che l'ho provato. Qualcosa come Flyweight o Singleton sarebbe una scelta sbagliata, dal momento che sono modi di usare gli oggetti in generale, non usare gli oggetti per realizzare qualcosa.)

2
David Thornley