OOP vs Functional Programming vs Procedural [chiuso]


237

Quali sono le differenze tra questi paradigmi di programmazione e sono più adatti a problemi particolari o eventuali casi d'uso favoriscono uno rispetto agli altri?

Esempi di architettura apprezzati!


Questa non è una risposta completa, ma scrivo un po 'su come "funzionale" influenza / contrappone lo stile "OO" (nel contesto di F #) qui: lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!511. entrata
Brian

Potresti considerare di leggere questo! Ci sono molti esempi di quando usare quale formica quali sono le principali differenze, vantaggi / svantaggi ecc.
Nikita Ignatov,



Zio Bob ha twittato su questo. E anche qui .
jaco0646,

Risposte:


129

Tutti sono bravi a modo loro - Sono semplicemente approcci diversi agli stessi problemi.

In uno stile puramente procedurale, i dati tendono ad essere altamente disaccoppiati dalle funzioni che vi operano.

In uno stile orientato agli oggetti, i dati tendono a portare con sé una raccolta di funzioni.

In uno stile funzionale, i dati e le funzioni tendono ad avere più cose in comune tra loro (come in Lisp e Scheme), offrendo al contempo una maggiore flessibilità in termini di utilizzo effettivo delle funzioni. Gli algoritmi tendono anche a essere definiti in termini di ricorsione e composizione piuttosto che loop e iterazione.

Naturalmente, il linguaggio stesso influenza solo lo stile preferito. Anche in un linguaggio puramente funzionale come Haskell, puoi scrivere in uno stile procedurale (anche se questo è altamente scoraggiato), e anche in un linguaggio procedurale come C, puoi programmare in uno stile orientato agli oggetti (come in GTK + e API EFL).

Per essere chiari, il "vantaggio" di ogni paradigma è semplicemente nella modellazione dei tuoi algoritmi e strutture di dati. Se, ad esempio, l'algoritmo coinvolge elenchi e alberi, un algoritmo funzionale potrebbe essere il più sensato. Oppure, se, ad esempio, i tuoi dati sono altamente strutturati, potrebbe avere più senso comporli come oggetti se questo è il paradigma nativo della tua lingua - oppure potrebbe essere facilmente scritto come un'astrazione funzionale di monadi, che è il paradigma nativo di lingue come Haskell o ML.

La scelta di ciò che usi è semplicemente ciò che ha più senso per il tuo progetto e le astrazioni che la tua lingua supporta.


5
Quello che hai detto, non sembra riflettere ciò che hai scritto. Dici che non hanno "pro e contro", e poi dici come sono approcci diversi. Perché qualcuno dovrebbe scegliere un approccio piuttosto che un altro, in base a una determinata situazione? punti di forza e di debolezza, pro e contro, qualunque cosa tu li chiami esistono! Non sto dicendo che uno sia intrinsecamente migliore, e nemmeno tu. Credo che sia quello che stavi davvero cercando di dire. a meno che non crediate davvero che qualsiasi approccio scelto non abbia aspetti positivi e negativi, relativamente ad un altro approccio.
JM Becker,

1
@TechZilla: sono d'accordo sul fatto che la mia formulazione fosse scarsa, ma quello che volevo dire è che non esiste davvero un elenco di funzionalità che puoi indicare e dire che la lingua X è migliore di Y senza qualificare che la lingua X è più adatta alla scrittura dell'algoritmo U e della lingua Y potrebbe essere più adatto alla scrittura dell'algoritmo V, mentre entrambi possono essere facilmente implementati in entrambe le lingue.
Greyfade,

2
La differenza tra procedurale e funzionale non mi è chiara. Sto imparando Scheme / Rackett al College, ma non riesco davvero a vedere la grande differenza tra esso e il C o PHP procedurale, potresti fare qualche esempio?
Leonel,

7
@Leonel: la più grande differenza che la maggior parte delle persone citerà è che nei linguaggi procedurali, potresti usare un ciclo for, ma i linguaggi funzionali, non esiste una cosa del genere - invece, usi le chiamate ricorsive alle funzioni per eseguire la stessa attività. I linguaggi funzionali rendono anche funzioni oggetti di prima classe - puoi passarli come faresti con un numero - ma non puoi farlo in C (e il supporto di PHP è rotto).
greyfade,

2
@tastro: quando un paradigma ha più senso dell'altro. Questo è davvero tutto. A volte ha più senso modellare il codice come composizione di funzioni, a volte ha più senso modellare i dati come oggetti. Esistono molti modi per esprimere algoritmi e strutture di dati. OOP e funzionale sono due di queste cose.
Greyfade,

25

Penso che le librerie, gli strumenti, gli esempi e le comunità disponibili superino completamente il paradigma in questi giorni. Ad esempio, ML (o qualsiasi altra cosa) potrebbe essere il linguaggio di programmazione universale per tutti gli usi , ma se non riesci a ottenere buone librerie per quello che stai facendo, sei fregato.

Ad esempio, se stai realizzando un videogioco, ci sono altri buoni esempi di codice e SDK in C ++, quindi probabilmente stai meglio con quello. Per una piccola applicazione web, ci sono alcuni fantastici framework Python, PHP e Ruby che ti faranno funzionare molto velocemente. Java è un'ottima scelta per progetti più grandi grazie al controllo in fase di compilazione e alle librerie e piattaforme aziendali.

In passato, le librerie standard per le diverse lingue erano piuttosto piccole e facilmente replicabili: C, C ++, Assembler, ML, LISP, ecc. Venivano fornite con le basi, ma tendevano a impazzire quando si trattava di standardizzare le cose come comunicazioni di rete, crittografia, grafica, formati di file di dati (incluso XML), anche le strutture di dati di base come alberi bilanciati e hashtable sono state escluse!

I linguaggi moderni come Python, PHP, Ruby e Java ora hanno una libreria standard molto più decente e hanno molte buone librerie di terze parti che puoi facilmente usare, grazie in gran parte alla loro adozione di spazi dei nomi per evitare che le biblioteche si scontrino tra loro, e garbage collection per standardizzare gli schemi di gestione della memoria delle librerie.


5
Python, ruby, ... non hanno librerie "standard" come C o LISP, poiché sono linguaggi di implementazione singoli. Python è ciò che dice Guido, non esiste uno standard. Ogni particolare implementazione C o LISP (o qualunque altra cosa) al giorno d'oggi viene fornita con un ampio set di librerie oltre a quelle standard.
Dan Andreatta,

8
La domanda riguardava le differenze tra programmazione orientata agli oggetti, funzionale e procedurale. Mentre le lingue menzionate in queste risposte si prestano sicuramente a uno di questi approcci, la risposta non menziona nessuno di questi concetti ... Indipendentemente dal fatto che "le librerie disponibili [...] [trump] il paradigma", che non risponde alla domanda attuale, facendo così da passo in avanti quella che è una domanda completamente valida.
Rinogo,

1
Rant correlati di ircmaxell
rinogo,

20

Questi paradigmi non devono essere reciprocamente esclusivi. Se guardi a Python, supporta funzioni e classi, ma allo stesso tempo tutto è un oggetto, comprese le funzioni. Puoi mescolare e abbinare lo stile funzionale / oop / procedurale in un unico pezzo di codice.

Ciò che intendo è che, nei linguaggi funzionali (almeno in Haskell, l'unico che ho studiato) non ci sono dichiarazioni! alle funzioni è consentita una sola espressione al loro interno !! MA, le funzioni sono cittadini di prima classe, puoi passarle come parametri, insieme a un sacco di altre abilità. Possono fare cose potenti con poche righe di codice.

Mentre in un linguaggio procedurale come C, l'unico modo in cui puoi passare le funzioni è usando i puntatori a funzione, e questo da solo non consente molte attività potenti.

In Python, una funzione è un cittadino di prima classe, ma può contenere un numero arbitrario di istruzioni. Quindi puoi avere una funzione che contiene un codice procedurale, ma puoi passarlo in giro proprio come i linguaggi funzionali.

Lo stesso vale per OOP. Un linguaggio come Java non ti consente di scrivere procedure / funzioni al di fuori di una classe. L'unico modo per passare una funzione è avvolgerla in un oggetto che implementa quella funzione e quindi passare quell'oggetto.

In Python non hai questa limitazione.


Credo che intendevi dire "questi paradigmi non devono essere reciprocamente esclusivi". I 3 sono ortogonali in quanto idealmente potresti usarne uno, 2 o 3 in un unico programma (se la tua lingua lo consente).
Joe Pineda,

Sì, immagino che si escludano a vicenda sia un termine migliore per questo! grazie
hasen

14

Per la GUI direi che il paradigma orientato agli oggetti è molto adatto. La finestra è un oggetto, le caselle di testo sono oggetti e anche il pulsante OK è uno. D'altra parte, cose come l'elaborazione delle stringhe possono essere fatte con molto meno sovraccarico e quindi più semplici con un semplice paradigma procedurale.

Non penso sia una questione di lingua. Puoi scrivere funzionale, procedurale o orientato agli oggetti in quasi tutti i linguaggi popolari, anche se in alcuni potrebbe essere un ulteriore sforzo.


17
Sono tentato di sottovalutare per aver perpetuato l'idea sbagliata che "Oggetto = widget GUI", ma mi trattengo. OOP funziona altrettanto bene per rappresentare concetti astratti, come "UserAccount" o "PendingSale", così come per gli elementi dell'interfaccia visibili come "Window" e "Button".
Dave Sherohman,

5
Ho scritto che una finestra può essere un oggetto. Come trarre la conclusione che ogni oggetto è una finestra da lì? Era solo un esempio. Ovviamente OOP può essere usato anche per modellare entità astratte e le loro relazioni. Comunque, grazie per non aver votato. Non ho comunque molti punti: D
panschk,

6
-1. OOP non ha nulla a che fare con la GUI. Idealmente, il metodo migliore per progettare le guis è usare un file di testo esterno (es. HTML). Mentre cose come l'elaborazione delle stringhe sono in realtà molto meglio fatte con gli oggetti. (pensa alle stringhe in C) !!
hasen

1
Non lo so, forse sono solo abituato a programmare con oggetti per realizzarlo. Ma come faresti alcune cose interattive come cambiare il valore in TextBox X quando il valore di TextBox Y è stato modificato senza usare oggetti? Ok, potresti semplicemente usare i var globali per tutto ...
panschk,

1
L'elaborazione delle stringhe viene eseguita meravigliosamente in perl (100 volte meglio che in Java, C ++ o C #), tuttavia la funzionalità delle stringhe del linguaggio NON è assolutamente orientata agli oggetti. La gestione delle stringhe di C è stata terribile, ma C non è l'unico linguaggio procedurale (né il migliore).
Joe Pineda,

6

Per rispondere alla tua domanda, abbiamo bisogno di due elementi:

  1. Comprensione delle caratteristiche dei diversi stili / modelli di architettura.
  2. Comprensione delle caratteristiche dei diversi paradigmi di programmazione.

Un elenco di stili / modelli di architettura software è mostrato nell'articolo sull'architettura software su Wikipeida. E puoi fare ricerche su di loro facilmente sul web.

In breve e in generale, Procedurale è buono per un modello che segue una procedura, OOP è buono per la progettazione e Funzionale è buono per la programmazione di alto livello.

Penso che dovresti provare a leggere la storia su ogni paradigma e vedere perché le persone la creano e puoi capirli facilmente.

Dopo averli compresi entrambi, è possibile collegare gli elementi degli stili / modelli di architettura ai paradigmi di programmazione.


2

Penso che spesso non siano "contro", ma è possibile combinarli. Penso anche che spesso le parole che menzioni siano solo parole d'ordine. Ci sono poche persone che sanno veramente cosa significhi "orientato agli oggetti", anche se ne sono gli evangelisti più accaniti.


1

Uno dei miei amici sta scrivendo un'app grafica usando NVIDIA CUDA . L'applicazione si adatta molto bene al paradigma OOP e il problema può essere scomposto in modo ordinato in moduli. Tuttavia, per usare CUDA devi usare C, che non supporta l' ereditarietà . Pertanto, devi essere intelligente.

a) Elaborate un sistema intelligente che emulerà l'eredità in una certa misura. Si può fare!

i) È possibile utilizzare un sistema hook , che prevede che ogni bambino C del genitore P abbia un determinato override per la funzione F. È possibile fare in modo che i bambini registrino i loro override, che verranno memorizzati e chiamati quando richiesto.

ii) È possibile utilizzare la funzione di allineamento della memoria struct per trasmettere i bambini ai genitori.

Questo può essere pulito ma non è facile trovare una soluzione affidabile, a prova di futuro. Trascorrerai molto tempo a progettare il sistema e non vi è alcuna garanzia che non incontrerai problemi a metà del progetto. L'implementazione dell'ereditarietà multipla è ancora più difficile, se non quasi impossibile.

b) È possibile utilizzare una politica di denominazione coerente e utilizzare l' approccio di divisione e conquista per creare un programma. Non avrà alcuna eredità ma poiché le tue funzioni sono piccole, di facile comprensione e formattate in modo coerente, non ne hai bisogno. La quantità di codice che devi scrivere aumenta, è molto difficile rimanere concentrati e non soccombere a soluzioni facili (hack). Tuttavia, questo modo ninja di codifica è il modo C di codifica. Rimanere in equilibrio tra libertà di basso livello e scrivere un buon codice. Un buon modo per raggiungere questo obiettivo è scrivere prototipi usando un linguaggio funzionale. Ad esempio, Haskell è estremamente buono per gli algoritmi di prototipazione.

Tendo ad avvicinarmi b. Ho scritto una possibile soluzione usando l'approccio a, e sarò onesto, mi è sembrato molto innaturale usare quel codice.


I primi copmpiler c ++ non erano altro che pre-processori che generavano codice C. Pertanto, TUTTE le funzionalità di c ++, inclusa l'ereditarietà multipla, possono essere implementate usando C. (emulare la gestione delle eccezioni di c ++ in C richiederebbe un qualche tipo di supporto della piattaforma per le eccezioni, ma anche le implementazioni di c ++ lo richiedono, quindi non penso che sia la base idea non valida).
Chris Becke,

2
@ Chris è diventato la tua risposta è troppo filosofica. Per uno, C ha diversi standard (nel corso degli anni), quasi nessuno di essi completamente adottato dai compilatori C e tanto meno c ++. Dire che C ++ è un superset di C perché usa la sintassi C non significa molto perché non si può nemmeno scrivere codice per un compilatore C che si compila in un altro compilatore C senza sforzi significativi. Inoltre, ci sono funzionalità linguistiche (sistemi di tipo, supporto OOD) offerte in altre lingue che sarebbe impossibile implementare in C senza usare C per progettare una nuova lingua (motivo per cui ci sono "nuove lingue")
Sprague

Sai. Non vedo più quale rilevanza abbia il mio commento a questo post. : P
Chris Becke il

Cuda supporta C ++ da qualche tempo.
Aryeh Leib Taurog
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.