La programmazione ad oggetti, meglio conosciuta come Object Oriented Programming (OOP), è una delle tecniche di programmazione più diffuse e consolidate nel modo dello sviluppo software. I principi fondamentali sono adatti sia ad applicativi WEB, che a software più complessi, come giochi 3d.
La tecnica non è legata ad un linguaggio particolare di programmazione, quindi non è necessario avere delle conoscenze pregresse per capirla, anche se è comunque consigliabile.
Programmazione ad oggetti: la storia
La formulazione della tecnica risale ai primi anni 60, con il SIMULA I e il SIMULA 67, linguaggi di programmazione sviluppati da Ole-Johan Dahl e Kristen Nygaard grazie al supporto del Norwegian Computing Center.
Tra i più noti linguaggi di programmazione ad oggetti, citiamo il C++, Java, Delphi, C# e, il Visual Basic .NET.
Partiamo dal principio. Il paradigma OOP è basato sugli oggetti che interagiscono tra di loro, attraverso messaggi o metodi, ma mantenendo nascosto il proprio stato interno, la logica di business, o parte dei dati. Torneremo su questo punto più in là.
Il concetto alla base della programmazione ad oggetti è appunto l'oggetto. L'oggetto è una istanza "reale" della Classe (che identificano gli oggetti), gli attributi delle classi e le funzionalità delle classi. Una classe è un’astrazione che rappresenta le proprietà comuni (struttura e comportamento) ad un insieme di oggetti concreti (istanze).
Programmazione ad oggetti: cos’è
Pensiamo ad una Classe che chiameremo "Ciclomotore"
I possibili Attributi potranno essere: Potenza motore, tipo di alimentazione, Numero ruote, numero porte, numero posti a sedere, capacità bagagliaio, etc
Le possibili funzionalità potrebbero essere: Accendi motore, spegni motore, Accelera, Aumenta la Marcia, Diminuisci la Marcia…
Un possibile oggetto, o istanza della classe ciclomotore, potrebbe essere un modello specifico di ciclomotore, come un Motorino Piaggio Liberty.
Ovviamente il Liberty ha una sua potenza, un suo motore specifico. Il funzionamento del motore è nascosto all'esterno, ma è possibile utilizzarlo, accenderlo, o muoversi
Una istanza, inoltre è un oggetto che è che esiste nel tempo (viene costruita e poi distrutta) e nello spazio (occupa memoria di sistema o di persistenza).
Due oggetti con le stesse caratteristiche, normalmente non sono uguali a livello applicativo (2 Liberty avranno sempre targe o seriali differenti, anche se identici dal punto di vista delle caratteristiche)
Programmazione ad oggetti: i 4 principi basilari
Avendo compreso questo, vediamo ora i 4 principi basilari della programmazione ad oggetti: incapsulamento, astrazione, eredità e polimorfismo.
Queste parole possono sembrare strane per uno sviluppatore junior. Per questo motivo, questa breve serie di articoli è dedicata ad una spiegazione semplice, breve e chiara per ciascuno dei 4 concetti.
Incapsulamento nella programmazione ad oggetti
Supponiamo di avere un programma che possiede alcuni oggetti “logicamente” diversi che comunicano tra loro, secondo le regole definite nel programma.
L’incapsulamento si ha quando l’oggetto mantiene il suo stato privato all’interno della classe. Altri oggetti non hanno accesso diretto a questo stato, ma possono accedervi, o modificarlo utilizzando le funzioni pubbliche, chiamate anche metodi. Quindi, l’oggetto gestisce il proprio stato, le proprie proprietà, tramite i metodi e nessun’altra classe può modificare lo stato se non esplicitamente consentito. Se si desidera comunicare con l’oggetto, è necessario utilizzare i metodi pubblici forniti.
Pensiamo all'esempio di prima:
Se volessi accendere il motore, utilizzerei il metodo Accendi Motore, anche se sotto non so cosa fa, con precisione totale. Il metodo invocato cambia lo stato dell'oggetto, e senza una chiamata, o invocazione esplicita, non potrei cambiare lo stato dell’oggetto.
Per questo, ed altri motivi, è importante che i metodi delle classi siano scritti per far capire cosa fanno, non come.
Astrazione nella programmazione ad oggetti
L’astrazione è un processo che punta a semplificare un problema complesso. Può essere pensata come un’estensione dell’incapsulamento. Nella progettazione orientata agli oggetti, i programmi sono, il più delle volte, estremamente grandi. Possono includere centinaia o migliaia di oggetti diversi, che comunicano tra di loro. Ora pensate ad un progetto con alcuni sviluppatori, che lavorano per mesi, se non anni. Mantenere il codice, con tutti i cambiamenti e gli aggiornamenti del caso, diventa difficile senza avere un “accordo”.
Per risolvere un problema, non ci si deve perdere in ogni dettaglio, bensì prestare attenzione solo a quelli che portano alla sua soluzione. L’astrazione in pratica consente di trovare una soluzione generale e riutilizzabile in tutte le situazioni riconducibili a una certa casistica. Un soluzione quindi che dovrebbe essere innanzitutto facile da utilizzare (per i successivi utilizzi) e che raramente dovrebbe cambiare nel tempo.
Pensiamo all’esempio di prima. Volutamente la classe di prima era stata chiamata “Ciclomotore” e non “Motorino” perchè in questo modo, oltre ai motorini, possa includere anche i tricicli a motore, e persino a quadricicli di piccole dimensioni. Questi mezzi hanno per lo più caratteristiche simili, ma con valori differenti.
Perché astrazione e incapsulamento sono concetti legati tra di loro? L’astrazione è una caratteristica per rendere efficace l’incapsulamento
Prendiamo ad esempio, la macchina per il caffè. Ha le forme e colori più disparati, ma tutto quello che bisogna fare per fare una tazzina di caffè è mettere la capsula e premere un pulsante. Quindi pensiamo all’astrazione come un piccolo insieme di metodi pubblici che qualsiasi altra classe può chiamare senza “sapere” come funzionano all’interno (se l’acqua della macchina viene riscaldata da una resistenza elettrica o a gas, o con un laser, a noi poco importa, l’importante è che la macchinetta svolga il suo compito).
L’astrazione potrebbe definirsi come "l’arte di sapersi concentrare solo sui dettagli essenziali nella rappresentazione di un’entità di dominio".
Per definire un oggetto è quindi necessario individuare:
- le sue caratteristiche, o attributi, attraverso la cosiddetta astrazione sui dati
- le azioni che può compiere e/o subire, o metodi, con la cosiddetta astrazione funzionale.
Utilizzando l’esempio del motorino di prima, gli attributi rappresentano tramite astrazione il motorino, ed i metodi che si possono invocare, le azioni che si possono fare con il motorino, o, più in generale, che cambiano lo stato del motorino.
Ovviamente, l’insieme degli oggetti creati, crea una astrazione di sistema di dominio.
Quindi si può parlare di almeno tre livelli di astrazione per quanto riguarda la sua implementazione nella programmazione ad oggetti:
- astrazione funzionale (i metodi degli oggetti)
- astrazione dei dati (gli stati o attributi degli oggetti)
- astrazione del sistema (l’insieme degli oggetti che comunicano tra di loro)
Nei prossimo articolo vedremo anche gli altri concetti fondamentali, e come questi, combinati tra di loro, sono utilizzati anche in programmi apparentemente semplici come quello di una calcolatrice.