|
~Créer une collection en VB

Les collections d'objets sont extrêmement utile en programmation. Contrairement à Java, l'offre de Visual Basic en terme de collections est pauvre. On en dénombre deux: Collection et
PropertyBag. Nous allons commencer par voir quels problèmes posent l'objet Collection avant d'en créer une
variante : Vector.
AVANT PROPOS : Les algorithmes utilisés pour nos implémentations ne sont pas efficaces du tout. Cependant ils
permettent d'illustrer simplement la création de collections. 

L'objet Collection est un objet permettant de stocker un ensemble de données dans un tableau extensible. Sans connaître
par avance le nombre d'éléments que nous souhaitons ajouter au tableau, nous pouvons quand même les y placer sans se soucier
d'un problème de limite. Les éléments sont donc indexés dans le tableau. On peut donc les lire de manière classique. Mais cette
collection offre une fonctionnalité supplémentaire: l'indexation par clé. Vous pouvez par exemple associer l'objet
"La plus jolie" à la clé "Claire".
Malgré ces qualités apparentes, l'objet Collection est un monstre. Premièrement à cause de sa fâcheuse tendance à
générer des erreurs et deuxièment à cause de sa structure logique affreuse. L'objet Collection est un mélange bâtard
d'un vecteur et d'une table de hachage. De plus les fonctions d'insertion d'éléments se confondent avec la méthode d'ajout.
Voici un exemple d'utilisation de cet objet:
Dim c As New Collection
Call c.Add("La plus jolie", "Claire")
MsgBox c.Item("Claire")
MsgBox c.Item(1)
Dans cet exemple, nous ajoutons simplement un élément en lui donnant une clé. Si vous exécutez ce programme, vous verrez
que la lecture par clé et par index retournent le même message. Bien entendu, si nous n'avions pas spécifié de clé pour l'objet,
la première lecture ne marcherait pas:
Dim c As New Collection
Call c.Add("La plus jolie")
MsgBox c.Item("Claire")
Ce programme génère une erreur lors de l'exécution. Et ceci est un des problèmes majeurs de l'objet Collection. Toute
tentative de lecture infructeuse se solde par une erreur. Ceci rend votre code beaucoup plus comple en vous astreignant à gérer
des erreurs supplémentaires.
Mais ceci n'est pas le seul problème. Si, par exemple, vous voulez insérer un élément dans la collection, vous devrez également
passer par la méthode Add().
Dim c As New Collection
Call c.Add("La plus jolie", "Claire")
Call c.Add("Jeff Trent", , "Claire")
MsgBox c.Item("Claire")
MsgBox c.Item(1)
La métode Add() permet en effet d'ajouter un élément, avec ou sans clé, avant ou après un autre élément. L'élément de
référence peut être désigné par son index ou sa clé. Néanmoins, cette possibilité ne complique que d'avantage la syntaxe
de la méthode Add(). En outre, une méthode nommée Insert() serait bien plus intuitive.
Pour pallier à ces limitations nous allons créer notre propre implémentation de cet objet. Ne souhaitant pas faire l'amalgame entre
un tableau dynamique et un tableau d'indexation par clés, nous allons créer deux objets:
- Vector, qui est un tableau dynamique
- HashMap, qui est un tableau d'indexation par clés, faisant appel à Vector
La création d'un tableau à redimensionnement automatique est chose facile en Visual Basic. Ce langage propose en effet
une instruction nommée ReDim permettant de changer la taille d'un tableau. Prenons cet exemple:
Dim m() As Integer
ReDim m(1 To 10)
m(1) = 666
ReDim m(1 To 15)
MsgBox UBound(m)
MsgBox m(1)
Ce code commence par créer un tableau de 10 entiers auquel on affecte une valeur. Ce tableau est ensuite redimensionné pour
contenir 15 éléments. Malheureusement, la valeur que nous avions placé à l'index 1 a disparue. Il faut pour cela employer
l'instruction optionelle Preserve. Notez que l'instruction ReDim ne peut pas fonctionner sur un tableau dont les
dimensions sont précisées dans la déclaration Dim.
Dim m() As Integer
ReDim m(1 To 10)
m(1) = 666
ReDim Preserve m(1 To 15)
MsgBox m(1)
Dans ce second cas, la valeur 666 est bien préservée dans le tableau.
L'instruction ReDim sera utilisée chaque fois que nous aurons à redimensionner le tableau. Ceci arrivera en plusieurs
occasions. Notre objet possède deux propriétés: sa taille et sa capacité. La première propriété indique le nombre d'éléments
effectivement disponibles dans le tableau. La propriété de capacité indique le nombre d'éléments que la collection peut encore
accueillir avant redimension. Lorsque la taille devient égale à la capacité, nous devons augmenter la taille du tableau. Par
convention nous doublerons cette taille.
Voici la liste exhaustive des fonctions que nous allons implémenter dans notre objet Vector:
- addElement, ajoute un élément à la collection
- clear, efface le contenu de la collection
- contains, retourne vrai si la collection contient l'élément spécifié
- getCapacity, renvoie la capacité actuelle de la collection
- getElementAt, lit l'élément à la position spécifiée
- getSize, renvoie le nombre d'éléments de la collection
- indexOf, donne la position d'un élément au sein de la collection
- insertElementAt, insère un élément
- isEmpty, vrai si la taille est égale à 0
- lastIndexOf, dernière position d'un élément de la collection
- removeElement, enlève la première occurence de l'élément de la collection
- removeElementAt, enlève l'élément occupant la position donnée
- setCapacity, change la capacité totale
- setElementAt, modifie la valeur d'un élément
- setSize, change la taille
- trimToSize, ramène la capacité de la collection à sa taille
Comme vous le voyez notre objet Vector est particulièrement riche en possibilités. Son utilisation est plus claire que celle
de Collection puisque ses nombreuses méthodes et fonctions ne jouent qu'un seul et unique rôle à la fois. Le code source
complet de notre nouvel objet est téléchargeable à la fin de ce cours.
Notre objet Vector possède une seule défficience en regard de Collection. Nous allons y remédier tout de suite.
Nous n'aurons besoin que de quelques méthodes seulement. Une méthode put() pour ajouter un élément avec sa clé
et une méthode get() pour lire un élément. Nous ajouterons également deux fonctions permettant de récupérer d'une part
la liste des clés et d'autre part la liste des éléments.
Voici le code source complet de notre objet. L'utilisation de Vector en rend la programmation très très simple:
Private keys As Vector
Private values As Vector
Private Sub Class_Initialize()
Set keys = New Vector
Set values = New Vector
End Sub
Public Function getElement(key As Variant) As Variant
Dim i%
i = keys.indexOf(key)
If i <> -1 Then
getElement = values.getElementAt(i)
Else
getElement = Empty
End If
End Function
Public Function getKeys() As Vector
Set getKeys = keys
End Function
Public Function getValues() As Vector
Set getValues = values
End Function
Public Sub putElement(ByVal obj As Variant, ByVal key As Variant)
Call keys.addElement(key)
Call values.addElement(obj)
End Sub
Nanti de ce nouvel objet, nous allons recréer le premier exemple de ce cours:
Dim h As New HashMap
Call h.putElement("La plus jolie", "Claire")
MsgBox h.getElement("Claire")
MsgBox h.getValues().getElementAt(0)
Et ça marche parfaitement ! Notez simplement que l'indexation des valeurs dans le tableau commence à zéro (comme en C).
Notre objet HashMap a encore besoin d'une fonction permettant de retirer un élément (la clé devra être enlevée aussi).
Mais ceci devra être réalisé par vos soins. La structure de nos nouveaux objets est bien plus lisible et logique que celle de la
Collection proposée par Visual Basic. L'objet PropertyBag évoqué en introduction devient également caduque
par l'introduction de HashMap.
Voici quelques fichiers à télécharger:
- article1.zip, le code source des objets Vector et HashMap
- Syxigh, code source d'un logiciel faisant une utilisation intensive
de nos deux objets
|