# Programmazione ad oggetti

Un programma è fatto da un insieme di "attori", a ciascuno dei quali è assegnato un compito ben preciso, che sono coordinati per risolvere un compito più complesso. Sono chiamati oggetti e sono macchine programmate per restare in attesa finché non viene loro ordinato di fare qualcosa. L'ordine viene chiamato più precisamente messaggio.
Un programma è scritto come un insieme di oggetti che si inviano messaggi a vicenda.
Per esempio, nella figura a lato, l'oggetto Fred (cliente) chiede all'oggetto Bob (cameriere) di portargli del cibo. Bob chiede a Hank (cuoco) di portare del cibo. Hank elabora la richiesta, e nel frattempo Bob svolge un altro compito (porta del vino). Quando Hank ha finito, notifica Bob, passandogli il cibo, e questi lo passa a sua volta al cliente, informandolo che il cibo è pronto. Dopo aver mangiato, il cliente paga il cassiere, dandogli il denaro; il cassiere gli restituisce lo scontrino. Infine, il cliente esce dal ristorante. Tutto l'accaduto è stato descritto in termini di messaggi scambiati fra soggetti diversi, e di contenuti passati o restituiti ad ogni messaggio.
Esercizio: disegna il diagramma di un cliente che va a pagare una bolletta alle Poste, e descrivilo in termini di oggetti che si scambiano messaggi e contenuti insieme ai messaggi.
Esercizio: disegna il diagramma di un automobilista che guida una macchina, e descrivilo in termini di oggetti che si scambiano messaggi e contenuti insieme ai messaggi.

## Incapsulamento

Nell'esempio di sopra, i messaggi inviati dal cliente sono sorprendentemente semplici:
* chiedere cibo al cameriere
* pagare il cassiere
Questi due messaggi hanno scatenato negli oggetti che li hanno ricevuti (cameriere e cassiere) reazioni che il cliente non può e non deve conoscere. Il cameriere, infatti, ha attivato delle operazioni (si è rivolto al cuoco) e ha interagito con un oggetto a cui il cliente non ha accesso (il taccuino). Il cassiere ha interagito con un oggetto a cui il cliente non ha accesso (la cassa). Il cuoco ha fatto lo stesso nei confronti del cameriere: le uniche interazioni sono state "ricevere ordinazione" e "dare piatto con il cibo"; dietro le quinte, ha coordinato i colleghi per preparare i componenti della ricetta, e ha interagito con gli strumenti da cucina. Il cameriere non avrebbe potuto fare da solo queste cose, perché non ha titolo per coordinare gli assistenti in cucina, e non ha accesso agli strumenti.
In un altro scenario, il cameriere potrebbe essere anche un cuoco, e interagire direttamente con gli strumenti da cucina. Oppure potrebbe avere rivolgersi ad un distributore automatico. In questi casi, (posto che i risultati siano gli stessi del cuoco, ovviamente) il cliente non può distinguere cosa fa il cameriere.
Il meccanismo di funzionamento di ciascun oggetto è nascosto agli altri oggetti. Questo si chiama "incapsulamento" e consiste nel nascondere i dettagli delle operazioni svolte, e le strutture dati usate dagli oggetti.

## Classi

In un programma a oggetti i compiti sono divisi in più "attori", ognuno dei quali svolge un ruolo ben preciso.
Nel gergo della programmazione ad oggetti, il ruolo viene chiamato classe e l'attore che impersona quel ruolo viene chiamato oggetto oppure istanza di quella classe. Un oggetto riceve un messaggio quando viene attivata (invocata) una sequenza di istruzioni chiamata metodo. Ogni oggetto ha un proprio ambito di competenza ben preciso, e ognuno dei messaggi che può ricevere rappresenta un compito ben definito.
Quando riceve un messaggio, l'oggetto cambia il proprio stato interno e/o invia dei messaggi ad altri oggetti (o a se stesso). L'intero programma viene scritto sotto forma di scambio reciproco di messaggi; alcuni hanno lo scopo di svolgere le elaborazioni dei dati per le quali il programma è stato scritto, mentre altri sono inviati ad oggetti speciali che sanno come interagire con l'hardware della macchina (schermo, supporti di memorizzazione, interfacce di rete, ecc.) e servono per lo scambio dei dati con l'input e l'output (utente, memorie di massa, rete, ecc.).
I linguaggi di programmazione orientati agli oggetti fanno capo agli stessi principi generali e agli stessi concetti di base (classe, oggetto, metodo, ecc.), tuttavia supportano meccanismi diversi, non solo a livello di sintassi (per es. alcuni hanno garbage collector, altri no; in alcuni è d'uso comune copiare gli oggetti per valore, in altri si usa sempre e solo un riferimento all'oggetto; ecc.). Il testo che segue riguarda specificamente la programmazione a oggetti in linguaggio Java.

## Significato

Realizzare un programma vuol dire scriverne il testo (chiamato in gergo codice sorgente), compilarlo, e distribuirlo all'utente finale. Quest'ultimo avvia il programma, che esegue le elaborazioni per le quali è stato programmato.
Il codice sorgente contiene l'elenco delle classi. Durante la fase di scrittura del software, e durante la compilazione, non esistono oggetti, ma solo classi. A tempo di esecuzione, il programma legge il testo di quelle classi per generare in memoria le rispettive istanze, ognuna delle quali impersona il proprio ruolo per tutta la sua vita all'interno del programma. La classe funziona come uno "stampino" che il programma usa un numero di volte stabilito dal programmatore.
Ogni oggetto è dotato di uno stato interno e di un insieme di metodi che gli altri oggetti possono attivare (invocare). Invocare un metodo vuol dire inviare un messaggio all'oggetto. Lo stato interno è memorizzato in una o più variabili, dette attributi o campi. Ogni classe specifica l'elenco degli attributi e dei metodi delle sue istanze, e il significato che questi attributi e metodi devono avere per i client. Ovviamente, oggetti diversi realizzano macchine diverse, quindi possono avere stati interni diversi; inoltre, lo stato interno di un oggetto può cambiare durante l'esecuzione del programma. I metodi, invece, sono prefissati dalla classe di cui l'oggetto è istanza, cioè non possono essere cambiati durante l'esecuzione del programma; inoltre, sono uguali per tutte le istanze di una stessa classe.
Tipicamente, le classi sono scritte avendo in mente una realtà ben precisa. Per esempio, in un gioco di corse di macchine può esserci una classe Automobile, e durante l'esecuzione del programma ci saranno vari oggetti appartenenti a questa classe. Ovviamente, chi scrive la classe individua solo gli aspetti di interesse, vale a dire che tutte le caratteristiche che non servono al programma non sono neanche prese in considerazione. Per eseguire il gioco di macchine è necessario che la classe Automobile permetta di gestire la velocità dell'auto sulla pista da corsa e la quantità di carburante, ma ad esempio sarebbe superfluo introdurre anche la marca del parabrezza o la data dell'ultima revisione per il Bollino Blu; però queste due informazioni sarebbero importanti (e quindi sarebbero implementate) nella classe Automobile di un programma che è stato scritto per un negozio di auto usate.

## Modalità di progettazione

Un compito complesso viene realizzato all'interno del programma come un metodo che richiama altri metodi, ognuno dei quali risolve un compito più semplice. La suddivisione dei compiti può avvenire essenzialmente secondo due approcci: top down o bottom up.
Ad esempio, secondo l'approccio top down, il programma che mostra sullo schermo un valore approssimato della radice quadrata di 3 può essere realizzato facendo eseguire in sequenza queste operazioni:
* crea una finestra sullo schermo
* calcola la radice quadrata di 3
* scrivi la radice sulla finestra (lasciala visibile finché l'utente non la chiude)
... dividendo questi compiti in compiti più piccoli: ad esempio, il primo passo viene diviso in
* chiedi al sistema grafico di allocare una nuova finestra
* imposta il titolo e le dimensioni della finestra
* rendi la finestra visibile sullo schermo
... e così via, fino ad arrivare a compiti elementari.

## Altre informazioni

Un programma può fare uso di un numero arbitrario di oggetti. Ogni oggetto viene creato, utilizzato da altri oggetti, e poi distrutto.
Un oggetto raggruppa insieme un certo numero di variabili di istanza, dette anche campi, e un certo numero di metodi. Le variabili dell'oggetto vengono create al momento della creazione dell'oggetto, e restano in vita finché quest'ultimo resta in vita. In gergo, si dice che un oggetto (chiamato client) chiama o invoca un metodo su un altro oggetto (detto oggetto di invocazione). In Java si parla sempre e solo di metodi, e mai di funzioni.
Le classi esistono nel testo del programma (ovvero nel codice sorgente e nel bytecode), mentre gli oggetti esistono solo a tempo di esecuzione. Il codice sorgente del programma elenca le classi che devono essere disponibili per la creazione degli oggetti. Quando un oggetto riceve un messaggio, la macchina virtuale cerca la sua classe ed esegue le operazioni che quest'ultima ha associato a quel preciso messaggio; tra le operazioni possibili, c'è anche l'invio di altri messaggi su altri oggetti. In definitiva, un programma è realmente composto da oggetti che si scambiano messaggi, e il punto di partenza è detto "punto di ingresso" del programma ed è anch'esso un messaggio (il metodo main).

## Approfondimenti

Per maggiori informazioni sul tema della programmazione a oggetti, si rimanda alla lettura del seguente materiale:
* The Java Tutorials, Lesson: Object-Oriented Programming Concepts