|
I mattoncini dei bambini.
Mi sembra ieri quando mi regalarono la mia prima scatola del gioco, credo, più famoso al mondo: il LEGO! Fu una grande conquista, ci passavo ore ed ore della mia giornata in preda ad una convulsa frenesia, cercando di costruire quella bellissima auto che spadroneggiava sul coperchio della scatola. Mi ricordo ancora che la sfida più difficile con i miei fratelli era di riuscire a costruirla senza seguire le istruzioni, solo in quel caso potevi considerarti un vero uomo ed assurgere all'olimpo del miglior costruttore del quartiere. Beh... altri tempi, altre storie, altre conquiste ma... sicuramente gli stessi schemi mentali! Non credo di dire niente di insolito nel paragonare il mattoncino del Lego alla più elementare espressione del paradigma della programmazione ad oggetti. Sviluppare meccanismi operativi ad oggetti o, più precisamente ideare soluzioni orientandosi agli oggetti, è un'attività che fa parte della natura umana fin dagli albori della civiltà; le grandi costruzioni e tipicamente quasi tutte le attività umane possono essere rappresentate secondo questo paradigma. Anche il corpo umano stesso è "pensato" ad oggetti: le cellule! Ogni cellula implementa un'interfaccia "cellula base" che ne definisce le principali caratteristiche: la cellula è la più piccola struttura vivente, è costituita da una membrana esterna, un nucleo ed alcuni organuli specializzati nelle rispettive funzioni vitali. A sua volta ogni singola cellula, facente parte di un tessuto, si specializza (si tipizza in termini informatici), ovvero subisce particolari trasformazioni per compiere al meglio la propria funzione.
Riassumendo i vari passaggi:
-
Definizione: Una cellula per chiamarsi cellula deve avere almeno: membrana, nucleo, citoplasma, ecc... (Definizione dell'Interfaccia)
-
Assegnazione delle funzionalità ai rispettivi costituenti la cellula (Implementazione della classe basata sull'interfaccia)
-
Specializzazione della cellula base con arricchimento di funzionalità (Ereditarietà dalla classe base)
-
Generazione della cellula specializzata (Creazione dell'istanza della classe, ovvero creazione dell'oggetto)
Anche per il mattoncino del LEGO il discorso non cambia:
-
Definizione del moduletto base: Il modulo base del LEGO è un parallelepipedo in plastica che presenta un cerchietto sulla parte superiore ed un incavo nella parte inferiore ove si incastra precisamente il cerchietto di cui sopra. (Definizione dell'Interfaccia)
-
Assegnazione delle funzionalità: cosa fa e come lo fa. (Implementazione della classe basata sull'interfaccia)
-
Specializzazione del moduletto: Definizione dei vari mattoncini e loro misure, specializzazione di oggetti complessi ma che usano comunque il moduletto base (Ereditarietà dalla classe base)
-
Generazione del mattoncino (Creazione dell'istanza della classe, ovvero creazione dell'oggetto)
Potrei continuare il discorso per milioni di altri esempi relativi al mondo reale ed invece credo che sia giunto il momento di definire che cosa si intende per programmazione orientata agli oggetti.
Per programmazione orientata agli oggetti si intende un paradigma di programmazione [1] secondo il quale ogni entità software viene sviluppata incorporandone sia i dati che le funzionalità di gestione in un'unica classe, la cui istanza rappresenta un oggetto del tipo della classe stessa. In parole povere ogni classe rappresenta la modularizzazione software di oggetti del mondo reale. I dati della classe vengono rappresentati attraverso le proprietà, le funzionalità vengono definite metodi della classe e ne definiscono il comportamento. Oltre a questo la classe è in grado di generare (scatenare in termini informatici) particolari eventi che hanno il compito di informare che l'oggetto in questione ha subito particolari variazioni.
I mattoncini dei grandi
Il paradigma di programmazione [1] OOP risulta essere il più indicato per la programmazione rivolta ad ambienti basati su interfaccia grafica avanzata, tipo Microsoft Windows, Apple OS, Linux, ecc... Questa caratteristica nasce dalla particolarità di questi ambienti operativi nell'essere organizzati secondo oggetti interscambiabili tra di loro. Basti pensare ad esempio che ogni stampante installata in Windows ci appare esattamente sempre uguale in qualunque area richieda l'uso di una stampante, ovvero ogni oggetto stampante interagisce con altri oggetti esponendo sempre le stesse funzionalità.
Come possiamo fare allora per accedere ai benefici di una programmazione ideale per gli ambienti di sviluppo su cui intendiamo distribuire i nostri applicativi? Ovviamente non tutti i linguaggi di programmazione possono essere definiti "ad oggetti". Un linguaggio di programmazione per poter essere definito "ad oggetti" deve rispettare 3 caratteristiche principali: Incapsulamento, Ereditarietà e Polimorfismo.
Incapsulamento
Un linguaggio è in grado di rispettare l'incapsulamento quando consente ad una classe di esporre le funzionalità e i dati soltanto attraverso metodi e proprietà definite, ovvero incapsula al suo interno le metodiche di gestione delle funzionalità e del dato esponendo esternamente soltanto il nome del metodo e/o della proprietà. Quando io scrivo un metodo di una classe utilizzando questo costrutto:
Public Sub MostraMessaggio (ByVal messaggio As String)
MessageBox.Show (messaggio)
End Sub
public void MostraMessaggio( string messaggio)
{
MessageBox.Show( messaggio );
}
la classe esternamente esporrà soltanto il metodo MostraMessaggio e non il codice che viene successivamente richiamato dalla Sub poichè risulterà "incapsulato" all'interno del metodo stesso. Stesso discorso vale per le proprietà che permettono di accedere ai dati della classe.
Ereditarietà
L'ereditarietà è la funzionalità che un linguaggio espone e che permette di derivare nuove classi a partire da classi già definite estendendone le proprietà e permettendo di modificarne il comportamento dei metodi. Il meccanismo di ereditarietà da una classe permette alla classe derivata di disporre dei metodi e delle proprietà presenti nella classe base, in alcuni casi di ridefinirne il comportamento ma con l'indubbio vantaggio di sfruttare classi già scritte incrementando la riusabilità del codice. Anche una classe derivata può diventare classe base per un' ulteriore classe che a sua volta eredita da questa, esponendo tutte le proprietà e i metodi a partire dalla prima classe base. Alcuni linguaggi OOP avanzati (come ad esempio il VB.NET e il C#) permettono di gestire l'uso dell'ereditarietà limitando le caratteristiche di derivabilità di una classe, ovvero rendono possibile limitare in tutto o in parte la visibilità delle proprietà e dei metodi di una classe base attraverso l'uso di particolari parole chiave del linguaggio, ma questo sarà oggetto di successiva discussione.
Polimorfismo
Non so come mai ma la prima immagine che mi viene in mente quando sento la parola polimorfismo sono i Barbapapà, quella simpatica famigliola di fiaschi di gomma colorata che si trasformavano in qualsiasi cosa volessero per poi ritornare esattamente nella forma originale. La cosa curiosa è che ognuno di loro, proprio per le loro caratteristiche era più adatto degli altri a trasformarsi nella cosa di cui c'era bisogno in quel momento. Anche i Barbapapà in qualche modo erano polimorfici ed altamente tipizzati! Per polimorfismo s'intende la capacità che ha un linguaggio nell'implementare comportamenti diversi per classi diverse sugli stessi metodi e proprietà ereditate dalla stessa classe base. Ad esempio le classi "Autoveicolo" e "Motoveicolo" ereditano entrambe dalla classe base "Veicolo" ma la rispettiva proprietà "Ruote", ereditata dalla classe base, nel primo caso è rappresentata da una collection di 4 elementi e nel secondo caso da da una collection di 2 elementi, grazie al polimorfismo la stessa proprietà (Ruote) viene implementata in due modi diversi.
...ed ora? Tutti in classe! ma non confondetevi... non ho detto "Tutti I-stanza!"
Perdonate il gioco di parole ma fin dall'inizio ho parlato di classe senza darne la corretta definizione. Questo è necessario poichè spesso la classe viene confusa con la sua istanza ovvero l'oggetto. La classe infatti è uno strumento che permette di definire la struttura dei dati attraverso le proprietà e al contempo le logiche per la gestione dei dati stessi attraverso i metodi.
Da un punto di vista matematico una classe definisce un insieme in modo intensivo, ovvero definendone le caratteristiche più che elencandone gli elementi; essendo essa stessa un insieme di dati, come tutti i costrutti che permettono di definire le strutture dati anch'essa è a sua volta un tipo di dato. Per poter essere utilizzata una classe ha bisogno di essere creata in memoria ovvero deve essere istanziata, solo così sarà possibile assegnare un effettivo valore alle proprietà esposte dalla classe.
Una classe istanziata in memoria si definisce oggetto assumendo lo status logico finale definito dal paradigma OOP.
Essendo le proprietà dell'oggetto costruite "su" l'oggetto stesso, implicitamente richiamano l'oggetto che le ha create. Alcuni linguaggi di programmazione (come ad esempio il C# ed il VB.NET) permettono comunque di referenziare esplicitamente l'oggetto dal suo interno utilizzando le parole chiave this (C#) e Me (VB). Alcuni linguaggi permettono, al momento della creazione di un'istanza della classe (tipicamente utilizzando la direttiva New), di indicare nel metodo alcuni parametri necessari all'inizializzazione dell'istanza dell'oggetto, questi particolari metodi vengono definiti costruttori; analogamente i metodi distruttori (tipicamente il metodo Finalize) permettono di eseguire codice di "pulizia" dell'oggetto nel momento in cui viene scaricata l'istanza dalla memoria.
[1] In informatica, un paradigma di programmazione è uno stile fondamentale di programmazione, ovvero un insieme di strumenti concettuali forniti da un linguaggio di programmazione per la stesura di programmi, e definisce/determina il modo in cui il programmatore concepisce e percepisce il programma.
|