La programmazione orientata agli oggetti è una soluzione alla complessità? [chiuso]


18

Pensi che la programmazione orientata agli oggetti sia una soluzione alla complessità. Perché? Questo argomento può essere un po 'controverso, ma le mie intenzioni di conoscere la risposta del perché dagli esperti qui!


15
Compito del saggio difficile? ; p
glenatron,

1
La domanda non ha senso in quanto non esiste una soluzione alla complessità. Esistono strategie per affrontare la complessità (in particolare, complessità intrinseca, irriducibile). Ma soluzioni, no non ci sono. È come cercare una soluzione per portare a zero la distanza di un miglio fisico.
luis.espinal,

1
La programmazione orientata agli oggetti è uno strumento per la gestione della complessità.
Robert Harvey,

Domanda: puoi programmare problemi complessi con OOP? - Risposta: certo. Se usi OOP, sarà complesso.
mouviciel,

"Può essere controverso" lo rende un argomento di discussione, piuttosto che una domanda tecnica ...
jwenting

Risposte:


24

Non esiste soluzione alla complessità.

In "The Mythical Man-Month", Fred Brooks discute la differenza tra complessità accidentale ed essenziale nella programmazione. La complessità accidentale è causata dai nostri strumenti e metodi, come la necessità di scrivere e testare codice aggiuntivo in una lingua perché non possiamo esprimere direttamente le nostre idee e cose del genere. Nuovi metodi e tecniche possono ridurre la complessità accidentale. Riesco a scrivere programmi più velocemente e meglio di quanto non potessi venticinque anni fa, perché ho lingue e strumenti migliori.

La complessità essenziale deriva dal fatto che ciò che proviamo a fare con la programmazione è intrinsecamente complicato e che esiste una complessità irriducibile. "Essenziale", in questo contesto, significa "relativo all'essenza della cosa" piuttosto che "molto necessario".

Pertanto, ha affermato che non ci sarebbero stati proiettili d'argento, che la scrittura di software avrebbe continuato a essere difficile.

Consiglio vivamente di leggere il suo libro: in particolare, raccomando l'edizione Silver Anniversary, con un saggio aggiuntivo "No Silver Bullet". In questo, rivede le soluzioni proposte alla complessità e ne considera l'impatto. (Quello che trova più efficace è il software termoretraibile: scrivi qualcosa di complesso una volta e vendi migliaia o milioni di copie.)

Ora, la programmazione orientata agli oggetti aiuta, se fatta bene, creando astrazioni e nascondendo la complessità. Un oggetto di una classe ha un certo comportamento definito da cui possiamo ragionare, senza preoccuparci della complessità dell'implementazione. Le classi scritte correttamente hanno un basso accoppiamento l'una con l'altra e il dividere e conquistare è un modo eccellente per affrontare la complessità se riesci a cavartela. Hanno anche un'elevata coesione, in quanto sono un insieme di funzioni e dati che sono strettamente correlati tra loro.


3
La 20th Anniversary Edition contiene anche "'No Silver Bullet' Refired", in cui si riferisce a OOP come "proiettile di ottone", e dice che è: "... un concetto molto promettente".
Jerry Coffin,

18

Mi aspetto che presto riceverai delle risposte migliori, ma eccone una semplice:

OOP aiuta * con complessità modellando il software in un modo più vicino al modo in cui modelliamo tutto il resto del mondo. È generalmente più semplice immaginare un oggetto palla che interagisce con un oggetto muro piuttosto che immaginare una serie di routine e strutture dati per fare la stessa cosa, poiché è più vicino al modo in cui interagiamo con il mondo reale.

* Perché nulla può "risolvere" la complessità


4
Ecco come funziona OOP in teoria. In pratica, esempi OOP come cani che abbaiano, anatre che volano e camion che sono veicoli, iniziano a rompersi quando si scrive un vero software, perché gli oggetti del programma reale sono sempre più astratti di questo.
Robert Harvey,

8
@Robert: Non sto sostenendo che modelli oggetti del mondo reale in OOP molto spesso, solo che è più facile pensare alla maggior parte della programmazione in termini di oggetto (anche se si tratta di oggetti socket-proxy e model-facade), perché è così vediamo il mondo dei cani e delle anatre nella vita reale.
Fishtoaster,

2
No, questo è un malinteso comune su OOP. Non dovresti modellare il tuo programma sulla base di oggetti della vita reale. Non esiste un BufferReader nella vita reale.
hasen

1
@Hasen j: Sì, è quello che ho detto quando ho chiarito nel mio commento.
Fishtoaster,

C'è davvero una bella discussione su programmers.stackexchange.com/questions/16189/…
Bill Michell,

15

Penso che l'attuale definizione tradizionale di OOP non sia una buona soluzione per gestire la complessità.

Se torni alle sue radici, credo che Alan Kay sia stato influenzato molto da "lisp".

Poiché Lisp non è stato corrotto dall'adozione tradizionale, è probabilmente riuscito a conservare i suoi valori fondamentali. Quindi penso che guardare come lisp affronta questo problema di complessità potrebbe darci un'idea, e possiamo usarlo come base per giudicare quanto sia utile OOP nel gestire la complessità.

Se si guarda alla fine della "Lecture 3a: Henderson Escher Example" di SICP , Hal Abelson propone che la complessità sia gestita non suddividendo l'attività in attività secondarie più piccole, ma creando strati di astrazione. Al livello più alto, esprimi la soluzione al problema complicato in termini di soluzione al livello più basso di astrazione.

Penso che OOP fosse originariamente inteso come un meccanismo per creare questi strati di astrazioni.

Purtroppo oggigiorno, OOP è (ab) usato per scrivere codice / strutture spaghetti.

Ne farò un esempio: un gioco multiplayer per FPS.

Al livello più alto, il gioco funziona avendo un gruppo di giocatori che correvano su una mappa e si sparavano l'un l'altro usando le armi.

Al livello inferiore successivo, dobbiamo parlare di mappe, armi e giocatori. Forse possiamo parlarne come oggetti fisici che interagiscono nel mondo del gioco.

Al livello inferiore successivo, possiamo parlare di come gli oggetti interagiscono fisicamente (movimento, collisioni, ecc.).

E così via e così via.

Ciò significa (e sto citando una sorta di citazione da SICP ..), è che ad ogni livello, non solo risolviamo un particolare problema specifico, ma una classe di problemi che in qualche modo cadono nelle vicinanze del problema che abbiamo " stai cercando di risolvere. Quindi, se c'è una piccola modifica nella descrizione del problema, probabilmente richiederebbe solo una piccola modifica nella soluzione.

Quindi, il modo saggio di usare OOP è creare strati di astrazioni, ad ogni livello di astrazione, risolvi il problema a portata di mano usando gli "oggetti" dal livello che è direttamente sotto.

Ecco la parte che stavo citando dalla lezione: http://www.youtube.com/watch?v=CYtrfncMqHQ


5
Come molti strumenti, OOP è altamente efficace quando viene utilizzato in modo intelligente e ponderato e non così efficace quando viene abusato.
Robert Harvey,

1
+1 per "strati di astrazione" - ottima spiegazione. OOP ti consente anche di limitare l'ambito di ciò che vedi a un oggetto alla volta, il che rende più semplice per le persone visualizzare il design e le interazioni.
Michael K,

1
Trovo l'idea che un concetto teorico che non sia "corrotto dall'adozione tradizionale" renderebbe migliore la gestione della complessità nei progetti del mondo reale ... bizzarro.
Michael Borgwardt,

@MichaelBorgwardt, l'adozione mainstream corrompe un'idea utile perché molte persone nel flusso principale non capiscono di cosa si tratta l'idea, quindi quando provi a cercare cos'è OOP, vedi varie idee sbagliate da varie persone. LISP è ancora usato, ma solo da una minoranza, quindi è meno probabile che le idee originali abbiano sofferto della corruzione causata da boss con i capelli a punta che non hanno idea di cosa si tratti.
hasen

@hasen j: OTOH è di conseguenza più probabile che le "idee originali" che non hanno mai visto l'adozione tradizionale fossero roba da torre d'avorio che non funziona nel mondo reale. La mancanza di popolarità non è certamente un punto chiaro a favore di nulla.
Michael Borgwardt,

10

Come al solito non sono d'accordo con tutti. Lungi dal fornire strumenti per gestire la complessità, OOP crea un'enorme quantità di complessità perché è un paradigma inadeguato e matematicamente falso. Confonde i programmatori senza fine, per provare a modellare cose con OOP che non possono essere modellate con OOP.

A mio avviso, il lavoro fondamentale qui è la costruzione di software orientata agli oggetti di Meyer. Descrive in dettaglio una serie di requisiti, tra cui uno che ritengo cruciale: il principio aperto-chiuso. Questo dice che una cosa deve essere aperta per l'estensione ma chiusa per l'uso, allo stesso tempo.

Meyer procede a derivare l'Orientamento agli oggetti da questi requisiti, come incarnato in Eiffel. L'incapsulamento fornisce la chiusura, l'apertura dell'eredità e la "cosa" menzionata è la classe.

Considero questo lavoro come una buona scienza perché Meyer aveva evidentemente torto, ed è possibile a causa della qualità del suo lavoro, individuare l'errore e risolverlo.

L'errore sta rendendo la classe, o il tipo, l'unità di modularità. È sbagliato, e provabile. Anche Meyer ha riconosciuto il problema (chiamato problema della covarianza), che OOP non è in grado di gestire relazioni di arità superiori a una (ovvero, OOP funziona bene per le proprietà ma fallisce nelle relazioni binarie). A Eiffel, questo problema ha comportato un sistema non corretto nel sistema di tipi!

La soluzione è abbastanza chiara L'unità di modularità deve essere più grande di un singolo tipo. Deve essere costituito da diversi tipi e dai metodi che li riguardano.

Non sorprende che questo modello di astrazione sia supportato dalla teoria matematica dell'astrazione, vale a dire la teoria delle categorie: i tipi sono oggetti di una categoria e i metodi (funzioni) sono frecce.

Con questo modello, le rappresentazioni di diversi tipi sono note a un insieme di funzioni. La rappresentazione è nascosta al pubblico, quindi si tratta di un'incapsulamento, ma usiamo i moduli, non le classi.

Standard Meta-Language (SML) e Ocaml sono basati direttamente su questo modello. Ocaml ha anche classi e OOP: non è inutile perché OOP ti fornisce l'invio di proprietà, ovvero l'associazione dinamica. Tuttavia, la maggior parte dei problemi del mondo reale riguarda le relazioni ed è poco sorprendente che le lezioni non vengano utilizzate molto in Ocaml.

Non sorprende che l'ereditarietà non sia affatto utilizzata nella libreria di modelli standard C ++.

Il semplice fatto è che OOP non ti dà gli strumenti giusti per gestire la complessità, non ti dà nemmeno gli strumenti per gestire problemi davvero semplici, invece ha fuorviato e confuso due generazioni di programmatori. Lungi dall'aiutare, OOP è la cosa più cattiva e cattiva che è successa alla programmazione da quando C, Fortran e Cobol hanno iniziato a stancarsi.


ho tentato di creare un altro account per votarvi ancora;)
Marco Mariani,

Fai diverse affermazioni. Forse puoi fornire argomenti a supporto delle tue affermazioni o riferimenti ad argomenti. In questo modo, che non supporta del tutto le tue varie tesi (nel senso che dice "ci sono cose sbagliate in OO; questo è ciò che deve fare"): lucacardelli.name/Papers/BadPropertiesOfOO.pdf
Frank Shearar

3
Dire "pippo è la cosa più cattiva e cattiva ..." è attivamente corrosivo per qualsiasi argomento che potresti provare a fare, comunque.
Frank Shearar,

6

La programmazione orientata agli oggetti ha radici che possono essere fatte risalire agli anni '60. Man mano che l'hardware e il software diventano sempre più complessi, la gestibilità diventa spesso una preoccupazione. I ricercatori hanno studiato i modi per mantenere la qualità del software e hanno sviluppato una programmazione orientata agli oggetti in parte per affrontare i problemi comuni enfatizzando fortemente le unità discrete e riutilizzabili della logica di programmazione.

Un programma orientato agli oggetti può quindi essere visto come una raccolta di oggetti interagenti, al contrario del modello convenzionale, in cui un programma è visto come un elenco di attività (subroutine) da eseguire. In OOP, ogni oggetto è in grado di ricevere messaggi, elaborare dati e inviare messaggi ad altri oggetti. Ogni oggetto può essere visto come una "macchina" indipendente con un ruolo o una responsabilità distinti. Le azioni (o "metodi") su questi oggetti sono strettamente associate all'oggetto stesso.

http://en.wikipedia.org/wiki/Object-oriented_programming

Questa separazione di preoccupazioni, insieme ad altre caratteristiche dell'orientamento agli oggetti come polimorfismo, ereditarietà, passaggio di messaggi, disaccoppiamento e incapsulamento, forniscono un quadro logico e concettuale attraverso il quale la complessità di grandi programmi può essere gestita in modo altamente efficace.


2

Esistono molti tipi di complessità nello sviluppo del software. A livello di programmazione, OOP cerca di affrontare la complessità utilizzando oggetti e classi per modellare il dominio problematico. Un noto guru ha affermato che la risoluzione dei problemi rappresenta semplicemente il problema in modo che la soluzione sia la rappresentazione stessa. Quindi, mediante l'astrazione usando le classi, l'incapsulamento usando i modificatori e i metodi di accesso, l'eredità per specificare la relazione e il riutilizzo, la composizione nello stabilire relazioni e collaborazioni tra classi, il polimorfismo come mezzo per semplificare la determinazione di comportamenti diversi in oggetti simili, la complessità può essere gestita.

Esistono anche altri modi per gestire la complessità del software, ad esempio la programmazione logica (Prolog) e funzionale (Haskell).

A un livello superiore alla programmazione, abbiamo bisogno di modelli e principi di progettazione per guidare OOP. Quindi OOP gestisce la complessità a un livello basso (codifica) mentre queste metodologie come i modelli e i principi di progettazione guidano la progettazione della soluzione a un livello superiore (sistema e applicazione) e rendono più gestibili le complessità di sviluppo e gestione del software.

Per rispondere alla tua domanda, sì, OOP è solo una soluzione per gestire la complessità tra molte altre soluzioni. È una soluzione a basso livello. Abbiamo bisogno di modelli e principi di progettazione per guidare OOP a un livello superiore.


3
Starei molto attento a dire che "abbiamo bisogno" di modelli di progettazione. Sono artefatti naturali con un buon design OO - non dovrebbero essere usati per guidarlo. "Oh, non abbiamo un modello per questo, quindi non possiamo farlo." Sono un mezzo per comunicare il design.
Michael K,

2

La programmazione orientata agli oggetti gestisce la complessità essenziale e facoltativa, ma non riduce neanche.

Preferisco la definizione fornita da Eric Steven Raymond in The Art of Unix Programming , perché delinea tra complessità essenziale, facoltativa e accidentale. http://www.faqs.org/docs/artu/ch13s01.html#id2964646

OOP non fa nulla per la complessità essenziale o facoltativa, sono una funzione dei requisiti del programma. Può avere un effetto sulla complessità accidentale, in quanto puoi creare un design più elegante a volte con OOP. A volte, tuttavia, il design è peggiore quando si utilizza OOP.


2

I problemi complessi non possono essere semplificati attraverso la tecnologia, ma possono essere gestiti solo attraverso la tecnologia.

OOP è una tecnologia, un concetto e un modo per affrontare un problema.

OOP ti offre gli strumenti per applicare un design che può semplificare la gestione della complessità, ma puoi anche avere un design errato che aumenta la complessità. In altre parole, se non usato correttamente, puoi avere complessità indotta dalla tecnologia nei tuoi problemi.

Tieni presente che ci sono molti altri aspetti che determineranno il successo del tuo progetto (ad es. Stile di gestione del progetto, definizione del problema, gestione delle modifiche, ecc ...). La tecnologia che usi è rilevante solo in quanto ti aiuterà a gestire il problema.

Alla fine, la programmazione orientata agli oggetti non può essere una soluzione alla complessità; è solo uno strumento per gestirlo. (se usato correttamente)


+1 Alla fine, la programmazione orientata agli oggetti non può essere una soluzione alla complessità; è solo uno strumento per gestirlo. (se usato correttamente)
Karthik Sreenivasan,

2

L'orientamento agli oggetti (come usato convenzionalmente) è uno strumento utile in molte circostanze, ma non è una soluzione sufficiente alla complessità.

In particolare, aggiunge spesso molta " complessità accidentale ". Esempi sono la complessità che circonda l'eredità dell'implementazione, la necessità di fornire molte "funzionalità standard" come equals () e hashCode () ecc. Una bella presentazione di Stuart Halloway su questo argomento: " Semplicità non facile "

Gli oggetti nella maggior parte delle lingue tendono anche a incapsulare molto stato mutevole , che in un mondo concorrente sta iniziando sempre più a sembrare una cattiva decisione di progettazione. Ancora una volta un video interessante di Rich Hickey esamina la distinzione tra identità e stato dell'oggetto e come potrebbe essere un errore confondere i due.


1

La programmazione orientata agli oggetti è un modo di rappresentare un problema, niente di più, niente di meno. È, di per sé, non meno complesso di qualsiasi altro paradigma di programmazione. Un sistema OOP ben progettato gestisce e riduce la complessità, ma è anche molto facile progettare un sistema che è molto più complesso del necessario e ostacola tutto.

Come spesso detto del C ++, OOP ti dà abbastanza corda per impiccarti.


Ma questo è vero per qualsiasi linguaggio o paradigma potente. Vuoi una corda troppo corta per impiccarti? non ti arrampicheresti mai su una montagna con esso!
Michael K,

@Michael, alcuni più di altri. Ma essenzialmente sì. Non ci sono proiettili d'argento, ci sono sempre degli svantaggi in qualunque linguaggio o paradigma che stai usando.
Dominique McDonnell il

1

Penso di , solo perché ti permette di dividere la complessità in piccoli "blocchi" auto-contenuti che nascondono i dettagli e quindi li usano per creare la funzionalità di cui hai bisogno, passo dopo passo, strato per strato.

Dividere e conquistare.


1

OOP è un tentativo di soluzione.

Il modo migliore per gestire la complessità è creare astrazioni. Se riesco a trasformare i miei dati in raccolte utili, con funzioni riconoscibili che operano su quelle raccolte, posso iniziare a pensare alle raccolte come "cose" discrete. Questa è la base per classi e metodi. A tale proposito, OOP correttamente progettato può aiutare a gestire la complessità.

Da qualche parte lungo la strada, qualcuno ha deciso che potremmo usare OOP per aiutare a risolvere il problema del riutilizzo del codice. Voglio dire, perché reinventare la ruota? Se qualcun altro ha svolto gran parte del lavoro per risolvere questo problema, sfrutta ciò che ha fatto, aggiungi le modifiche che il tuo particolare progetto richiede e voilà! Hai creato un'applicazione potente e sofisticata con relativamente poco lavoro da parte tua. I programmatori OO possono essere programmatori molto produttivi.

Il risultato finale è che i moderni programmatori OO finiscono per essere "apprendisti stregoni", dove legano insieme un mucchio di grandi e ingombranti librerie con poche righe di "colla" e ottengono qualcosa che funziona. Sorta. Tipo. La maggior parte delle volte. Ci sono potenziali effetti collaterali dall'uso di questa libreria con quella? Può essere. Ma chi ha il tempo di scavare davvero nel codice contenuto in quelle librerie? Soprattutto quando le biblioteche si stanno evolvendo. Il risultato è che finiamo con applicazioni gonfie, in cui un programmatore aveva bisogno di una manciata di classi e metodi da quella libreria, ma l'app deve portare il peso di tutte le ALTRE cose di cui non avevano bisogno.

Il risultato finale è che ti ritrovi con molta più complessità del necessario.

Un altro meccanismo per gestire la complessità che si desidera separare la funzionalità. Volete tutte le vostre funzioni di accesso ai dati in un unico posto. Volete tutte le funzionalità dell'interfaccia utente in un unico posto. Vuoi tutti i tuoi controller in un unico posto. Quindi crei diverse classi che gestiscono diverse parti della funzionalità. Fin qui tutto bene. E questo scala, fino a un certo punto; i tuoi sviluppatori esperti nell'accesso ai dati possono scrivere quelle classi, le persone dell'interfaccia utente possono scrivere le classi dell'interfaccia utente, ecc. Tutto va bene.

Fino a quando non devi mantenere qualcosa scritto da qualcun altro.

Sì, è bene sapere che tutte le funzioni di accesso ai dati si trovano qui. Ma come li chiama?

Questo metodo lo chiama su quella classe. Ma quando guardo la definizione della classe, non esiste un metodo con quel nome. Oh, questo è ereditato da qualcos'altro uno o due strati nella catena dell'eredità. Apetta un minuto; che classe ha implementato un'interfaccia? Quante classi diverse implementano tale interfaccia? E stiamo usando un sistema di runtime complicato (ti sto guardando, Spring) per "collegare" istanze di classi in fase di runtime? Dove può essere utilizzata QUALSIASI classe che implementa tale interfaccia?

Ti ritrovi con molti metodi piccoli e discreti che fanno cose precise. Ma questo lo chiama, in un'altra classe. Il che lo chiama, in un'altra classe ancora. Il che lo chiama, in un'altra classe ancora. Il che lo chiama, in una classe aggiuntiva. Che restituisce un risultato di un tipo particolare. Su cui devi chiamare un metodo per fare una certa cosa. Che restituisce un risultato di un altro tipo. Eccetera.

C'è un termine per questo: codice spaghetti.

Si finisce con un sistema molto complesso necessario solo per comporre il codice. Quindi IDE come Visual Studio, Eclipse e NetBeans. Tutto ciò ha una significativa curva di apprendimento. In effetti, molti di loro sono in grado di incapsulare / aggregare più strumenti, sviluppati da diversi gruppi, ognuno dei quali ha le proprie curve di apprendimento PROPRIO.

Questa è gestire la complessità?

Il debug del codice è due volte più difficile della sua scrittura. Buona fortuna per il debug di alcune di queste cose. Soprattutto se utilizza più librerie, "cablate insieme" in fase di esecuzione utilizzando una sorta di sistema di iniezione di dipendenza.

In sintesi: OOP fornisce quello che sembra uno strumento promettente per aiutare a gestire la complessità. La realtà è che il codice risultante tende ad essere orribilmente gonfio (perché non è possibile estrarre solo i pezzi necessari da tutte quelle librerie collegate) e sono necessari strumenti sofisticati solo per navigare nel codice. Diventa rapidamente un incubo per la manutenzione.

IMHO, è una perdita netta; aggiunge più complessità di quanto elimini. Ti permette di fare cose che sarebbero estremamente difficili, forse anche impossibili, senza di essa. Ma qualsiasi progetto di grandi dimensioni si evolve rapidamente in un caos non mantenibile.

Se sai già come funziona e te lo ricordi, potresti avere la possibilità di mantenerlo.

Ricorda di applicare la Legge di Eagleson: qualsiasi tuo codice, che non hai visto in sei mesi, potrebbe anche essere scritto da qualcun altro.


0

Di qualche grado...

Perché? Perché facilita una modularità molto logica. Almeno in confronto alla programmazione procedurale in cui è troppo allettante scrivere solo enormi pile di spaghetti code.


0

Il motivo per cui la programmazione orientata agli oggetti sembra aiutarci a gestire la complessità è perché ci obbliga a scrivere codice in un modo specifico anziché in una grande varietà di modi. La programmazione orientata ai compiti è molto più intuitiva, motivo per cui la programmazione è iniziata in questo modo. L'orientamento agli oggetti richiede l'addestramento e la pratica per comprendere e utilizzare in modo efficace, ma vincolando la programmazione in un determinato percorso, consente agli addestrati di mantenere efficacemente il codice che è stato scritto.

Non è più logico o reale di qualsiasi altro metodo, è solo un modo di focalizzare il nostro problem solving attraverso obiettivi simili. Molte specialità tecniche usano il paradigma di una metodologia rigida non intuitiva per gestire la complessità dei loro compiti.

Un terzo metodo per gestire la complessità sarebbe la programmazione funzionale e probabilmente ci saranno anche altri nuovi metodi in futuro.


1
Commenti rimossi; cerca di mantenerli civili.
Fishtoaster,

0

penso che sia più una soluzione alla manutenibilità, perché, come programmatore, dovresti mettere metodi in cui hai i dati, creando così un modello a oggetti della tua applicazione.

sì, è anche una soluzione alla complessità fornendo un modello per "vedere" il tuo codice in modo naturale, come oggetti che hanno proprietà e possibili azioni

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.