Confronto Array di Strutture verso Collezione di Classi

Da Gambas-it.org - Wikipedia.

Confronto Array di Strutture verso Collezione di Classi

Per chi proviene in Gambas da MS VB la definizione e la gestione di strutture dati personalizzate può essere fonte di confusione. In genere, l'utente medio VB è abituato ad utilizzare array di strutture ('custom types').
Altri preferiscono utilizzare le Classi, con relative proprietà e metodi, e le Collection; in questo caso l'approccio a Gambas non comporta variazioni sostanziali.

La differenza sostanziale tra Array e Collection è data dalla differente metodologia di accesso agli elementi.
Gli Array sono per loro natura 'posizionali', ovvero la posizione in memoria è sequenziale e stabilita dalla dimensione e dall'indice progressivo del singolo elemento.
Le Collection sono gestite autonomamente dal compilatore e la posizione degli elementi non è determinata; l'accesso avviene tramite un indice chiave ('Key').
Lo scopo di questo documento è di fornire alcune informazioni sulle differenze tra i due approcci, con vantaggi e svantaggi, e una sintetica valutazione prestazionale.
Per ciascun approccio saranno presentate le 3 operazioni fondamentali di gestione liste, ovvero Accesso, Aggiunta, Eliminazione.


Definizione di STRUTTURE

Per gli esempi che seguino consideremo una semplicissima struttura dati composta da due proprietà, definita in Gambas con:
PUBLIC STRUCT Contatto
ID As Integer
nome As String
telefono As String
END STRUCT


Definizione di CLASSI

L'uso di classi comporta la consueta creazione di un documento di classe (es. clsContatto) che esponga le stesse proprietà viste sopra e dei metodi per la gestione delle stesse. Si crea dunque il nuovo documento 'clsContatto' (Attenzione: deve avere la definizione all'inizio CREATE STATIC).
'Class clsContatto
CREATE STATIC
PROPERTY Nome As String
PROPERTY Telefono As String

PRIVATE $iID As Integer 'proprietà utilizzata internamente per generare una nuova chiave
PRIVATE $sNome As String
PRIVATE $iTelefono As String

E' consigliabile usare questo approccio che prevede di 'nascondere' le proprietà interne della classe ed accedere ad esse solo tramite chiamate ai metodi pubblici esposti. In questo modo, oltre alla maggiore flessibilità di modifica della classa, si delega alla classe il compiti di validazione dei parametri.



ARRAY

In Gambas gli array di strutture possono essere statici o dinamici, ovvero a dimensioni prestabilite oppure variabili.

Array statici

Gli Array statici sono di scarso interesse in quanto la loro dimensione è 'hard coded' nel sorgente, quindi sono per niente flessibili. Ciò che segue è quindi sono allo scopo di completezza d'informazione e non sarà utilizzato negli esempi.
NOTA: in VB non esiste il concetto di Array statico in quanto può essere in qualsiasi momento ridimensionato con le istruzioni REDIM [PRESERVE}
La dichiarazione di un array statico di 10 strutture Contatto si scrive:
PUBLIC miaAgenda[10] as STRUCT Contatto

Array dinamici

La dichiarazione di Array dinamici è sottilmente, ma sostanzialmente, diversa:
PUBLIC miaAgenda as NEW Contatto[]
Si noti l'ovvia assenza del numero di elementi, l'uso di NEW e la diversa posizione delle parentesi quadre.
NOTA 1: per Gambas gli Array dinamici non sono altro che degli oggetti (classi), per cui valgono proprietà e metodi ereditati dalla classe madre 'Object'.
Ne consegue che l'utilizzo come Array piuttosto che come classi è più una scelta dell'utilizzatore che pratica, tranne nell'enumerazione degli elementi.
NOTA 2: se si vuole utilizzare un Modulo esterno al Form principale (per pulizia del codice) per la gestione dei dati, è obbligatorio copiare esattamente la dichiarazione della struttura ANCHE nel Form.

Per ridimensionate l'array (in VB si scriverebbe Redim Preserve miaAgenda(11)); in Gambas occorre procedere in 3 fasi:
1. si aumenta la dimensione dell'array con: miaAgenda.Resize(11)
2. si istanzia un nuovo elemento 'Contatto' con: nuovoContatto as New Contatto
3. si aggiunge il nuovo elemento vuoto con: miaAgenda.Add(nuovoContatto)

Enumerazione e accesso agli elementi

Accedere a tutti (enumerazione) o ad un elemento dell'Array è identico al metodo usato in VB, con l'unica avvertenza di usare le parentesi quadre invece che tonde, per cui:
Dim cliente AS Contatto
Dim numero AS String
Dim k as Integer

'per recuperare il valore di un campo dal record n°5:
numero = miaAgenda[5].telefono

'per recuperare l'intero record dall'agenda:
For k=1 To miaAgenda.Count
cliente = miaAgenda[k]
....
Next


Inserimento di elementi

Si incrementa come prima cosa la dimensione dell'array, come già visto, e poi si procede ad aggiungere i nuovi valori:
Static IdCount As Integer
Dim nuovoContatto As Contatto

IdCount = IdCount + 1
miaAgenda.Resize(miaAgenda.Count+1)
nuovoContatto as New Contatto
nuovoContatto.ID = IdCount nuovoContatto.Nome = "Pippo"
nuovoContatto.Telefono = 333-123456
miaAgenda.Add(nuovoContatto)


Cancellazione elementi

In VB l'eliminazione di un elemento richiede lo spostamento di tutti gli elementi superiori a quello voluto e successivamente il ridimensionamento dell'array. Gambas mette invece a disposizione il metodo Remove che elimina l'elemento e sposta automaticamente gli elementi superiori se esistono.
'nota: Indice è il numero dell'elemento da cancellare, passato alla funzione come parametro
miaAgenda[Indice].Remove



COLLECTION

La Collection è una rappresentazione dei dati estremamente potente, versatile e semplice in quanto si compone di solo una coppia di informazioni:
- la KEY (chiave) di accesso: una stringa che deve avere un valore univoco e non nullo (se Null, l'elemento 'sparisce', ovvero viene eliminato).
- il VALUE (valore): può essere qualsiasi cosa (variabile semplice, array, oggetti e anche altre Collection).
La Key può essere semplicemente un numero indice convertito in stringa per cui spesso l'uso delle Collection è concettualmente simile all'uso degli Array.
La definizione e l'instanziamento di una Collection, che è un Oggetto, è del tutto uguale a quelle degli tipi di variabile, per cui:
Pubblic miaAgenda as Collection
...
miaAgenda = New Collection


Enumerazione ed accessi agli elementi

Dim cliente AS clsContatto
Dim tel as String

'Utilizzando il campio chiave (es. Codice Fiscale), si accede direttamente al singolo elemento:
tel = miaAgenda[CodiceFiscale].Telefono 'Attenzione: la chiave deve essere una stringa!

L'enumerazione degli elementi utilizza la notazione For Each come per tutti gli altri oggetti.
For Each cliente In miaAgenda
Print cliente.Nome
....
Next


Inserimento di elementi

Occorre innanzitutto definire una nuova chiave; supponiamo di usare per questo il campo Telefono (certamente univoco).
Potrebbe però essere anche un valore esterno alla classe clsContatto, come un numero progressivo.
Static IdCount As Integer
Dim nuovoContatto As clsContatto

IdCount = IdCount + 1
nuovoContatto as New clsContatto
nuovoContatto.Nome = "Pippo"
nuovoContatto.Telefono = 345-987654
miaAgenda.Add(nuovoContatto, CStr(IdCount)) 'notare l'uso di IdCount come chiave


Cancellazione elementi

Come anticipato, per cancellare un elemento è sufficiente porre a Null la chiave, oppure utilizzare anche qui il metodo 'Remove':
miaAgenda[IdCount]=Null
'oppure:
miaAgenda[IdCount].Remove
In realtà, è altamente consigliabile verificare prima che la chiave esista, per esempio: If miaAgenda[IdCount].Exist Then miaAgenda[IdCount].Remove
E' importante notare come nel caso delle Collection non sia necessario ridimensionare la struttura in quanto si adegua da sè.


SCHEMA DI IMPLEMENTAZIONE DI CLASSI E COLLECTION

Per riassumere quanto vito nel caso di utilizzo di classi e collection (strategia suggerita), viene di seguito riportato uno schema sintetico dei documenti e delle dichiarazioni necessarie.

Documento Dichiarazioni
Form Main Chiamate ai metodi clsAgenda.miaAgenda[chiave]...
Classe 'clsAgenda'

PUBLIC miaAgenda As Collection
...
PUBLIC Sub _New()
miaAgenda = New Collection
End

PUBLIC Sub AddContatto(nome As String,telefono As String)
...
End

PUBLIC Sub RemoveContatto(ID as integer)
...
End

PUBLIC Sub GetContatto(ID as integer)
...
End

Classe 'clsContatto'

PROPERTY Nome As String
PROPERTY Telefono As String

PRIVATE $iID As Integer 'proprietà utilizzata internamente per generare una nuova chiave
PRIVATE $sNome As String
PRIVATE $iTelefono As String



CONFRONTO

Sia gli array di strutture che le collection di classi sono per Gambas degli oggetti, per cui l'approccio è sotto molti punti di vista simile.
Per chi proviene da VB le Strutture sono forse più familiari e forse più semplici da utilizzare dalle Classi. Occorre però anche considerare la diversa modalità di creazione e aggiunta di elementi in Gambas rispetto a VB, che 'appesantisce' in una certa misura la gestione.
Le Classi da parte loro hanno numerosi vantaggi in termini di leggibilità e di manutenzione del codice, nonchè offrono capacità di estensione d'uso sconosciute alle Strutture. Basti pensare all'ereditarietà delle Classi per cui si può avere una classe base e numerose classi figlie, senza dovere ripetere tutto il codice, e racchiudere il tutto in una Collection.
Inoltre, e questo è fondamentale per la sicurezza verso bachi e modifiche del codice nella Main, le classi consentono l'incapsulamento del codice, delegando tutte le procedure di accesso e verifica di congruità dei dati alla classe stessa. Questo permette tra l'altro di riutilizzare la stessa classe in altri progetti.
Dal punto di vista prestazionale, la valutazione sui tempi di esecuzione è delegata ad una seconda parte di questo documento che sarà rilasciata al più presto, insieme ad un programma di esempio e di test.


--Orionis (discussioni) 08:11, 30 giu 2014 (MDT)