adszone.org
venerdì 20 settembre 2024
"Il modo corretto di pensare il software"
home
consulenza  vb.net  contatti 
  Visual Basic .NET
  Programmazione ad oggetti - I
Domande

Premessa

Questo articolo si propone di illustrare i concetti fondamentali della programmazione orientata agli oggetti, descrivendone in dettaglio il modo in cui VB.NET la implementa. Si richiede una conoscenza base delle tecniche di programmazione ed in particolar modo i linguaggi procedurali ed i costrutti di base della sintassi del VB.NET

Introduzione

Programmare ad oggetti (OOP - Object Oriented Programming) significa essenzialmente organizzare il codice secondo una struttura che permette di individuare gruppi di istruzioni e aree di memoria, isolarli dal resto del programma e concepirli come entita' indipendenti che interagiscono tra loro.

A tale scopo, in parte contribuisce il compilatore che deve essere progettato per la gestione di oggetti, in parte il progettista di classi di oggetti ed in parte il programmatore che deve essere consapelove del ruolo svolto dagli oggetti, per utilizzarli al meglio.

E' utile ripercorrere sommariamente il cammino logico che porta ad orientare la programmazione verso gli oggetti. Consideriamo il seguente esempio di codice fittizio (pseudocodice):

Inizio Programma1 
	PulisciSchermo()
	DisegnaLinea(A, B)
	DisegnaLinea(B, C)
	DisegnaLinea(C, D)
	DisegnaLinea(D, A)
	DisegnaLinea(V1, V2)
	DisegnaLinea(V2, V3)
	DisegnaLinea(V3, V1)
Fine Programma1

Ogni programma non e' altro che una sequenza di istruzioni, eventualmente reiterate. Possiamo osservare che il gruppo di procedure marcate in rosso disegnano un rettangolo, quelle marcate in blu disegnano un triangolo. Ora, cosi' come abbiamo potuto evidenziare logicamente le istruzioni usando colori diversi, allo stesso modo potremmo isolare tali istruzioni, inserendole in due procedure diverse.



Inizio Procedura DisegnaRettangolo: parametri p1, p2, p3, p4
	DisegnaLinea(p1, p2)
	DisegnaLinea(p2, p3)
	DisegnaLinea(p3, p4)
	DisegnaLinea(p4, p1)
Fine Procedura DisegnaRettangolo

Inizio Procedura DisegnaTriangolo: parametri p1, p2, p3
	DisegnaLinea(p1, p2)
	DisegnaLinea(p2, p3)
	DisegnaLinea(p3, p1)
Fine Procedura DisegnaTriangolo

Inizio Programma2
	PulisciSchermo()
	DisegnaRettangolo(A, B, C, D)
	DisegnaTriangolo(v1, v2, v3)
Fine Programma2

Il programma precedente fa esattamente le stesse cose del primo. Qui, e' ancora vero che abbiamo una sequenza di istruzioni, ma non vengono necessariamente eseguite nell'ordine in cui compaiono. Le istruzioni che compaiono nelle procedure vengono eseguite solo nel momento in cui tali procedure vengono invocate, cioe' dopo PulisciSchermo().

Uno dei vantaggi di questo approccio, rispetto al precedente, e' quello che, variando i parametri, possiamo disegnare quanti rettangoli o triangoli vogliamo in qualsiasi punto del programma senza dover riscrivere ogni volta il gruppo di istruzioni relative. Ci bastera' invocare le procedure gia' scritte, usando parametri diversi. E, se volessimo cambiare l'algoritmo per il disegno, lo doveremmo fare una sola volta, cioe' all'interno delle procedure.

Codice organizzato ad oggetti

Andando oltre, potremmo identificare le due figure geometriche con delle entita' consapevoli del ruolo che svolgono: ad esempio, sappiano disegnarsi 'da sole', senza doversi appoggiare a procedure sparse qua e la' nel programma. Cioe':

Inizio Programma3
	PulisciSchermo()
	CreaOggetto Rettangolo R(A, B, C, D)
	CreaOggetto Triangolo T(v1, v2, v3)
	R.Disegnati()
	T.Disegnati()
Fine Programma3

Nel programma3, R e T sono due oggetti. Con la parola oggetto intendiamo identificare niente piu', niente meno che un oggetto reale o un concetto. Lo possiamo considerare come una variabile particolare, detta variabile oggetto. A differenza delle variabili semplici o quelle strutturate, essa e' in grado di eseguire procedure o funzioni. La procedura del nostro esempio e' Disegnati(). Notiamo che i due oggetti eseguono una procedura con lo stesso nome, ma poiche' le strutture dei due oggetti sono separate, queste procedure hanno implementazioni differenti in base ai contesti in cui sono definite, cioe' il contesto dell'oggetto rettangolo ed quello del triangolo. T.Disegnati() disegnera' un triangolo, R.Disegnati() un rettangolo. Vediamo come:

Inizio Definizione Oggetto Rettangolo

	Inizio Struttura Interna
		variabili punto1, punto2, punto3, punto4 
	Fine Struttura Interna

	Inizio Metodo Costruttore: parametri p1, p2, p3, p4
		punto1 = p1
		punto2 = p2
		punto3 = p3
		punto4 = p4
	Fine Metodo Costruttore

	Inizio Metodo Disegnati
		DisegnaLinea(punto1, punto2)
		DisegnaLinea(punto2, punto3)
		DisegnaLinea(punto3, punto4)
		DisegnaLinea(punto4, punto1)
	Fine Metodo Disegnati

Fine Definizione Oggetto Rettangolo

Inizio Definizione Oggetto Triangolo

	Inizio Struttura Interna
		variabili punto1, punto2, punto3 
	Fine Struttura Interna

	Inizio Metodo Costruttore: parametri p1, p2, p3
		punto1 = p1
		punto2 = p2
		punto3 = p3
	Fine Metodo Costruttore

	Inizio Metodo Disegnati
		DisegnaLinea(punto1, punto2)
		DisegnaLinea(punto2, punto3)
		DisegnaLinea(punto3, punto1)
	Fine Metodo Disegnati

Fine Definizione Oggetto Triangolo

Inizio Programma3
	PulisciSchermo()
	CreaOggetto Rettangolo R(A, B, C, D)
	CreaOggetto Triangolo T(v1, v2, v3)
	R.Disegnati()
	T.Disegnati()
Fine Programma3

Ci sono diversi nuovi concetti introdotti dall' esempio precedente. Innanzitutto osserviamo che abbiamo modellato gli oggetti definendoli in due sezioni distinte e separate dal resto del codice.

La Struttura Interna e' quell'insieme di variabili che caratterizzano l'oggetto. Esse assumono valori che rispecchino lo 'stato' del particolare oggetto.

Il costruttore e' una procedura. Tutte le procedure e le funzioni all'interno di un oggetto vengono dette metodi. Il costruttore e' un metodo che viene invocato implicitamente quando si crea l'oggetto; nel nostro caso esso non fa' altro che inizializzare la struttura interna dei nostri oggetti in base alle caratteristiche da noi specificate durante l'istruzione di creazione.

Quando creiamo un oggetto si dice che lo istanziamo, cioe' ne creiamo un'istanza in base al modello che abbiamo definito. Tale modello, che abbiamo chiamato 'Definizione Oggetto', nella pratica viene detto 'Classe'.

Una classe accomuna tutti quegli oggetti che hanno le stesse proprieta'. Ad esempio, la classe dei triangoli rettangoli contiene tutti quei triangoli che hanno la proprieta' di avere un angolo retto. Analogamente si puo' dire per la classe dei triangoli isosceli, etc.

Definire una classe per tali oggetti significa studiare ed implememtare una struttura interna capace di simulare le loro proprieta' e comportamento. I valori (stato) della struttura sono modificati nel corso del ciclo di vita dell'oggetto, pensate ad un contatore che s'incrementa.

La modifica dello 'stato' interno di un oggetto si ottiene agendo sui metodi implementati dalla classe. Il nostro costruttore, ad esempio, ha fissato i valori della struttura interna ad uno stato iniziale. Altri metodi potrebbero ingrandire o ridurre le dimensioni dei triangoli o rettangoli, andando a modificare i valori dei punti che costituiscono la struttura. Ricapitolando: la struttura modella l'oggetto, i metodi ne definiscono il comportamento. Il comportamento rende vivo l'oggetto poiche' altera, nel corso del programma, i valori della struttura, ne varia lo stato.

Pensate, ad esempio, ad una 'lampadina' il cui stato puo' essere acceso o spento. Avremmo due metodi 'accenditi()', 'spegniti()' che andranno a modificare una variabile interna che tiene traccia del fatto che la lampadina sara' disegnata accesa o spenta.

Ora, le classi Rettangolo e Triangolo da me presentate, non sono quanto di meglio c'e' per spiegare come progettare una classe. Ma quello che volevo era un semplice esempio per introdurre i vari concetti che ci permettano di comprendere la programmazione ad oggetti, senza addentrarci nelle tecniche di analisi e sintesi.

Sia l'oggetto Triangolo che quello Rettangolo, come abbiamo detto, hanno il metodo Disegnati(); ma, come possiamo vedere, ciascuno lo implementa in maniera differente. Non c'e' conflitto perche' le due procedure sono disponibili solo all'interno dei rispettivi oggetti. Proprio per pensarli separati dal resto del codice, vengono detti metodi, che, a differenza di procedure e funzioni, non possono essere invocati senza riferirsi all'oggetto a cui appartengono. Generalmente la sintassi e' quella di scrivere il nome dell'istanza dell'oggetto che abbiamo creato, seguito dal punto, seguito, a sua volta, dal nome del metodo che vogliamo invocare, es. 'variabile_oggetto.Metodo()'. Ci tengo a precisare che la procedura Disegnati() non esiste all'interno del programma, essa appartiene esclusivamente all'oggetto che la definisce.

Vediamo adesso un esempio piu' indicativo del ruolo svolto dagli oggetti all'interno di un programma.


... definizione classi omessa...

Inizio Programma4
	CreaOggetto Schermo
	CreaOggetto Pittore
	CreaOggetto Tavolozza
	CreaOggetto Paessaggio

	Schermo.Inizializzati()
	Tavolozza.Inizializzati()
	Pittore.SelezionaNuovaTela()
	Pittore.Disegna(Paesaggio, Tavolozza, Schermo)
Fine Programma2

Omettiamo la definizione degli oggetti perche' esula da quanto ci siamo proposti di illustrare. Inoltre e' bene notare che, in genere, il programmatore difficilmente definira' nuovi oggetti, ma si limitera' ad usare quelli gia' pronti, forniti dall'ambiente di sviluppo che utilizza.

In questo esempio vediamo come la programmazione supportata dagli oggetti ci permetta di concepire la risoluzione del problema dal punto di vista di una simulazione. Gli oggetti simulano oggetti reali e la logica di programmazione e' quella a cui siamo piu' abituati nella vita. Come vedete, ci limitiamo a richiamare dei metodi sui vari oggetti dicendo loro cosa fare ed essi lo fanno per noi. Mettiamo inoltre gli oggetti in comunicazione gli uni con gli altri, in modo che siano essi stessi a richiamare metodi su altri oggetti. Nel nostro caso, passiamo degli oggetti all'oggetto pittore tramite la funzione disegna. L'oggetto pittore interagendo con tali oggetti (chiamando i rispettivi metodi) sara' in grado di riportare il paesaggio sullo schermo utilizzando i colori nella tavolozza. E' come se interpellassimo un pittore, gli dessimo dei colori, una tela e gli chiedessimo di dipengerci un paesaggio.

E' chiaro che qualcuno dovra' pur progettare gli oggetti. Questo spetta, in genere, a chi implementa un sistema o libreria di classi, dove oltre che creare i singoli modelli di oggetti, ne studia anche le interazioni possibili e le sintetizza fornendo dei metodi adeguati.

E' chiaro che se dovessimo sviluppare un'applicazione abbastanza dedicata, lo studio del sistema componenti (oggetti) spetterebbe a noi. Ed e' comunque una buona prassi, prima di sviluppare del software, soffermarsi almeno qualche istante e pensare cosa vogliamo fare e come vogliamo farlo. Se non altro per non essere costretti a fermarci a meta' del progetto e capire che dobbiamo ricominciare tutto da capo o magari mettere delle 'pezze' che da li' a poco renderanno ingestibili futuri sviluppi del software.

Incapsulamento

La seguente figura riassume quello che abbiamo detto. (Non vi sembra?)

Questa e' la nostra rappresentazione ideale di un oggetto. Il guscio piu' esterno nasconde quella che noi abbiamo indicato come struttura interna (variabili). Vediamo che chi utilizza l'oggetto non sa nulla di come e' stato strutturato, vede soltanto i metodi. E' bene, infatti, non far supposizioni sul lavoro del progettista, in modo da non vincolarci e vincolare il progettista stesso ad una particolare rappresentazione.

Nascondere la struttura in questo modo e' detto information hiding e lo otteniamo mediante l'incapsulamento dei dati, come mostra la figura.

Lo strato esterno costituisce l'interfaccia tramite la quale interagiamo con l'oggetto. Non a caso e' costituita dai metodi. Solo invocando i metodi possiamo modificare lo stato di un oggetto. Non ci interessa come cio' sia ottenuto, a noi interessano soltanto gli effetti prodotti.

Nella seconda parte vedremo come Visual Basic .Net si orienta agli oggetti ed analizzeremo gli altri concetti fondamentali che completano il quadro dell' OOP.

Ultimo aggiornamento 13/01/2004