MaCocoa 003

Capitolo 003 - Object Oriented Programming

Dove si introduce un paradigma.

Sorgenti: Un po' copiato, un po' inventato...

Primo inserimento: Settembre-Ottobre 2001

Programmazione orientata agli oggetti

La programmazione orientata agli oggetti o, come si dice, la programmazione object oriented OOP, è un modo diverso da quello classico di considerare la programmazione dei computer.

Ci sono due metodi fondamentali per interagire con le cose. Il primo metodo specifica prima l'azione, poi la cosa (l'oggetto) sulla quale eseguire l'azione. Se parliamo di finestre, quelle reali, si deve lavorare così: Aprire: Finestra. Se poi volete passare alla porta, abbiamo un messaggio simile: Aprire: Porta. Il meccanismo, una volta capite le basi, funziona piuttosto bene.

Ma c'è un altro metodo: proviamo a dire prima l'oggetto, e poi l'azione che si vuole compiere su questo oggetto: Finestra: Aprire. Sembra un passaggio da poco, ma abbiamo spostato l'obiettivo dalle azioni agli oggetti.

Essere incentrato sulle azioni, sulle funzioni, sulle operazioni, è un approccio classico dei calcolatori. Dopotutto, il linguaggio macchina dei calcolatori è effettivamente qualcosa del tipo: indicazione dell'operazione, dati sui quali l'operazione deve essere eseguita. Si profila così una divisione piuttosto netta tra le operazioni e i dati. Mi ricordo che, nell'età giurassica quando studiavo queste cose, uno dei libri fondamentali del giovane informatico era un testo di Wirth (il professore -svizzero, mi pare- che ha inventato il linguaggio Pascal) intitolato: Algoritmi + strutture dati = programmi. Come dire, date le operazioni da eseguire , e i dati sui quali eseguirle, abbiamo fatto l'applicazione. Indico questo modo di programmare procedurale, oppure orientato alle procedure, nel senso che sono le sequenze di operazioni a fare il programma.

Parallelamente a questa scuola di pensiero se ne sviluppava un'altra, all'inizio un po' sotterraneamente e solo negli ambienti accademici, e poi con sempre maggiore diffusione, si proponeva la scuola della programmazione orientata agli oggetti; qui il punto centrale del discorso è l'oggetto, inteso come un ente software non meglio definito con alcune importanti caratteristiche: auto-contenuto, disponibile al colloquio e ad essere modificato senza sforzo eccessivo. Un oggetto è auto-contenuto in quanto contiene al suo interno (incapsula, si dice) sia i dati sia le operazioni che su questi dati operano. Un oggetto è quindi un ente software non semplicemente passivo, come può esserlo un numero, ma qualcosa un po' più attivo, un numero in grado di eseguire da solo le operazioni che interessano.

Per chi, come me, ha imparato a programmare con l'approccio procedurale, la OOP all'inizio appare un po' bizzarra. Ma poi, una volta compresa, diventa molto più naturale. Addirittura, adesso mi trovo ad usare tipici linguaggi di programmazione in ambito procedurale (il C, per capirci), distorcendoli in modo tale da farli diventare object oriented. E comunque alcuni concetti alla base della OOP sono indispensabili anche in ambito procedurale per essere un buon programmatore.

Diversi modi di programmare

La programmazione per oggetti, o programmazione orientata agli oggetti OOP è una metodologia di programmazione la cui caratteristica principale è il concetto di oggetto. Nella OOP tutto si basa, in maniera uniforme, sul concetto di Oggetto: ogni singolo programma, al più semplice al più complesso, si basa su un insieme di Oggetti che interagiscono tra di loro.

Un oggetto non è altro che un insieme di dati, assieme alle procedure necessarie per operare su questi dati; l'operazioni sui dati di un oggetto è esclusivo delle procedure facenti parti dell'oggetto.

Per apprezzare la differenza della OOP rispetto alla programmazione classica, partiamo dall'inizio.

Quando si deve risolvere in termini informatico un problema, a meno di casi molto semplice, è difficile riuscire ad avere qualcosa di compiuto e maneggevole. È giocoforza suddividere il problema in un insieme di sotto-problemi, di natura più semplice. Tradizionalmente, l'approccio utilizzato è stato quello di una suddivisione di tipo procedurale o funzionale. Si tratta di dividere le operazioni da svolgere in un insieme di moduli funzionali. L'intero programma è dunque composto da un insieme di moduli funzionali che operano, sequenzialmente o in parallelo, su strutture dati predefinite.

Supponiamo che il problema sia di leggere, ordinare e stampare in insieme di dati (che so, una lista di indirizzi). Esiste allora la struttura dati generali (una rappresentazione opportuna della lista di indirizzi) e di tre moduli funzionali separati, uno per la lettura dei dati ed il riempimento della struttura, uno per effettuare l'ordinamento di questi dati, uno per la stampa in bella copia o presentazione dei dati. Ognuno di questi tre moduli funzionali può essere diviso in altri moduli, ad esempio la presentazione dei dati può avvenire secondo diverse modalità, a video e a stampa; ogni tipo di presentazione è svolto da un separato modulo funzionale.

Questa metodologia classica o procedurale nasce e si afferma con i linguaggi di programmazione strutturata, come il Pascal ed il C. Del resto, la netta separazione tra i comandi e i dati è nella natura dei processori, le cui istruzioni di linguaggio macchina sono proprio costruite come comando e dati sui quali opera il comando stesso. Questi metodi procedurali, estremamente potenti, efficaci e naturali (per il processore), entrano in difficoltà di fronte a questioni di stampo ingegneristico: l'adattabilità a mutate condizioni e la riusabilità delle funzioni.

Un programma costituito da una base dati comune e dai blocchi funzionali adatti a lavorare su questa base dati diventa facilmente intrattabile quando si modifichi, anche leggermente, la struttura della base dati. In questo caso, una modifica sulla base dei dati ha impatto sull'intero programma, in quanto ogni blocco funzionale deve essere (potenzialmente) modificato, per tenere conto appunto di questa modifica. Viene da sé che è molto difficile riutilizzare uno dei blocchi funzionali (ad esempio, il blocco di ordinamento) sopra un'altra base dati, proprio perché l'ordinamento è tagliato sopra quella determinata base dati.

Le basi della OOP

Di fronte a questo metodo di progettazione, si è nel tempo affermato un diverso metodo, appunto OOP. In questa metodologia, la scomposizione non si basa più sull'operazione da eseguire, ma l'oggetto, inteso come modello dell'entità sulla quale si opera. Il programma è adesso costituito da un insieme di entità interagenti, ciascuna provvista di un struttura dati e dell'insieme di metodi adatti a manipolare quella struttura dati. Questi metodi sono inoltre l'unico modo con cui interagire con l'oggetto. Ciascun oggetto dunque incapsula i propri dati e ne difende l'accesso diretto da parte dell'esterno: i cambiamenti del mondo esterno non influenzano i dati all'interno, e viceversa, i dati interni non influenzano i dati esterni. Ne segue una netta separazione tra l'interno e l'esterno, che permette di recuperare i due punti deboli dell'approccio procedurale. Modifiche anche pesanti di strutture dati non hanno impatto sul resto del sistema, una volta garantita l'uniformità di comportamento dell'oggetto. A questo punto, per utilizzare un oggetto, basta sapere solamente quali sono le operazioni che si possono svolgere su di esso per poterlo utilizzare in contesti anche molto diversi tra loro.

La OOP è un modo diverso di pensare e di progettare sistemi. Non si contrappone totalmente al metodo procedurale (un singolo oggetto, alla fin fine, si costruisce con un approccio procedurale), ma è un metodo alternativo per la realizzazione di programmi complessi. Del resto, scomporre i problemi in oggetti, e poi questi oggetti in oggetti più semplici, è più vicino al mondo con cui l'essere umano interagisce con il mondo reale, per cui la OOP dovrebbe essere una strategie di risoluzione dei problemi più semplice e naturale.

In fin dei conti, la nostra lingua parla per soggetto e predicato, ovvero per oggetto ed operazione svolta o subita da questo oggetto. È il soggetto (informaticamente, l'oggetto) la base di ogni discorso.

La OOP non si limita a modificare l'oggetto della scomposizione: l'uso degli oggetti presenta molte altre caratteristiche interessanti che facilitano le metodologie di programmazione. Un linguaggio orientato agli oggetti ha almeno le seguenti caratteristiche:

Oggetti
È basato sul concetto di oggetto, e deve fornire quindi gli strumenti per definire, creare, gestire e distruggere oggetti.
Ereditarietà
Fornisce la possibilità di costruire nuove categorie di oggetti, riutilizzando le caratteristiche di altri oggetti e definendone di nuove; dopotutto, un'automobile è una versione specializzata dell'oggetto autoveicolo.
Polimorfismo
Consente di trattare allo stesso modo (chiamare con lo stesso nome procedure che eseguono lo stesso compito) oggetti differenti, e di avere la possibilità di mantenersi abbastanza generici nel farlo (avere oggetti non tipizzati). Dopotutto, l'operazione di rifornimento si fa su di una automobile, su di un motorino e su di una barca, sostanzialmente nello stesso modo, pur nella differenza degli oggetti che sono riforniti.
Binding dinamico
Consente l'uso incrementale degli oggetti: se il programmatore modifica una singola procedura, deve essere possibile ricompilare ed effettuare il caricamento di quella singola procedura e non dell'intero programma; in altre parole ancora, quale operazione sia effettivamente realizzata deve poter essere deciso all'ultimo momento utile, in maniera dinamica, perché nel frattempo qualcosa potrebbe essere cambiato (ma di questo concetto, qui mi rendo conto poco chiaro, se ne parlerà ancora).

Intervallo storico

Uno dei primi linguaggio OO ad essere creato è stato lo Smalltalk (correva l'anno 1972). Una particolare versione di Smalltalk era alla base del sistema operativo di Lisa, il progetto della Apple immediato predecessore del Macintosh. Solo verso la metà degli anni ottanta l'ondata OOP ha raggiunto i linguaggi di programmazione procedurali, portando a versioni orientate agli oggetti dei classici Pascal e soprattutto C. Più o meno contemporanei sono i due linguaggi OOP derivati dal C, ovvero il fortunato C++, utilizzato ormai dalla maggior parte dei programmatori, ed il meno fortunato Objective C, sul quale Cocoa si basa. Dal punto di vista dell'orientamento agli oggetti, tuttavia, ObjC è sicuramente il meglio riuscito, essendo una filiazione diretta dello Smalltalk: le estensioni del C che portano all'ObjC sono dirette applicazioni delle regole sintattiche dello Smalltalk. I puristi diranno invece che il C++ è un linguaggio bastardo che introduce concetti e costrutti OOP su uno strato essenzialmente procedurale, e riesce a mescolare malamente le due cose.

Licenza Creative Commons
Eccetto dove diversamente specificato, i contenuti di questo sito sono rilasciati sotto Licenza Creative Commons.
Pagina a cura di Livio Sandel (macocoa2012@gmail.com).