Le code de la programmation objet
Comment, une fois l'analyse faite, traduire tout cela en Visual Basic ? C'est ce qu'on va voir maintenant.
Créer une nouvelle classe
Pour disposer dans notre application des objets de classe Jeton et Cases, il nous faut bien évidemment commencer par créer ces deux classes, qui n'existent pas a priori dans Visual Basic (à la différence des classes de contrôles, qui sont là toutes prêtes à être utilisées).
Une classe se définit par un certain nombre de lignes de codes écrites dans un emplacement spécifique appelé Module de Classe.
Donc, de même que nous connaissions les Form et les Modules, nous avons à présent affaire à un troisième type de bidule dans lequel taper du code. On définit une classe et une seule par module, ce qui implique de manière imparable qu'on devra avoir autant de Modules de classes que de classes d'objet. En l'occurrence, pour notre mini-scrabble, il nous faudrait créer deux modules de classes : un pour les jetons, un pour les cases du plateau.
De plus, le nom de la classe sera celui du module. Pour changer le nom de cette classe (de ce module) il suffit d'aller voir les propriétés de notre module de classe, comme nous changions jusque là par exemple le nom d'un contrôle posé sur une feuille.
Dans notre exemple, nous devrons donc créer un module Jeton et un module Case.
Définir les propriétés de la classe
Le principe de base est le suivant :
- À chaque propriété d'une classe doit correspondre une variable du module de classe. C'est cette variable qui stockera la valeur de la propriété pour chaque objet de la classe.
- La lecture de la propriété (obligatoire) sera gérée par une procédure de type Property Get.
- L'écriture de la propriété (facultative) doit être gérée par une procédure de type Property Let.
En théorie, nous devrons nous demander pour chaque propriété si elle devra fonctionner en lecture - écriture, ou en lecture seulement (quitte à asséner une banalité, je rappelle qu'une propriété ne peut pas exister en écriture sans exister en lecture). Autrement dit, est-ce que je donne à mon propre programme le droit de modifier telle ou telle propriété ? Cette question n'est pas d'un grand intérêt pour une petite application autonome, mais elle peut devenir plus épineuse dans le cas d'une application plus grosse, où il serait dommage qu'un bout de code malheureux casse tout sur son passage. Cela dit, 99 fois sur 100, on rend systématiquement les propriétés accessibles tant en écriture qu'en lecture. Donc, sauf raison impérieuse, chaque propriété sera l'occasion d'écrire deux procédures Property.
Donc, je me répète, mais pour chaque propriété, la procédure Property Get, correspondant à la lecture, est obligatoire, la procédure Property Let, correspondant à l'écriture, est facultative (mais très souvent présente quand même !).
Définissons par exemple la propriété "valeur" d'un jeton, en admettant que nous souhaitions que cette propriété soit accessible tant en lecture qu'en écriture. Nous écrirons dans notre module de classe Jeton :
Private Tutu as Integer
Public Property Let Valeur (ByVal Nb As Integer)
Tutu = Nb
End Property
Public Property Get Valeur() As Integer
Valeur = Tutu
End Property
Pour cela, le mieux est d'imaginer ce qui va se passer lorsqu'on va utiliser un des objets Jeton. Quelque part dans le code principal, on va créer les jetons les uns après les autres (on verra comment faire cela dans un moment). Et puis, pour chaque jeton créé, on va affecter ses propriétés. Supposons que nous en soyons à créer un des jetons "B" du jeu, qui au Scrabble, valent trois points. Si le nom de ce jeton est Caramel(i), car nous définirons vraisemblablement tous les jetons du jeu comme un groupe, nous aurons une ligne qui ressemblera à :
Caramel(i).Valeur = 3
Regardons ce qui va se passer lorsque le programme exécutera cette ligne. La propriété Valeur étant utilisée en écriture, la procédure Property Let Valeur sera immédiatement exécutée. Celle-ci devant transmettre une information à l'objet (ici, le nombre de points), elle comporte obligatoirement un paramètre en entrée (que j'ai appelé Nb). Ce paramètre Nb, dans mon exemple, vaut 3. La ligne de code suivante place la valeur de Nb dans la variable Tutu, qui vaut donc à présent elle aussi 3. Et le tour est joué : Tutu, variable privée de la classe Jetons, a pour rôle de stocker la propriété Valeur de mes objets de type Jeton.
Dans l'autre sens, ça marche tout aussi bien : si j'utilise au cours de mon programme ma propriété Valeur en lecture, comme par exemple en faisant :
Points = Points + Caramel(i).Valeur
Ce code, qui appelle la propriété Valeur, déclenche illico la procédure Property Get Valeur. Celle-ci va en réalité marcher comme une fonction : elle va consulter combien vaut la variable Tutu, et renvoyer dans Valeur le contenu de cette variable.
Soit dit en passant, vous devez comprendre que ce mode de fonctionnement nous permet d'effectuer, si nous le souhaitons, un contrôle élaboré sur les propriétés de nos objets. Par exemple, les valeurs des lettres, au Scrabble, sont exclusivement 1, 3, 8 et 10. Afin d'être sûr et certain que la propriété Valeur d'un jeton ne pourra jamais être autre chose que cela, je pourrais transformer ma procédure Let en :
Public Property Let Valeur (ByVal Nb As Integer)
If Nb = 1 or Nb = 3 or Nb = 8 or Nb = 10 Then
Tutu = Nb
EndIf
Et toc ! Toute tentative d'affecter à la Valeur d'un Jeton un autre nombre que 1, 3, 8, ou 10 se solderait par un échec cuisant. On peut ainsi blinder ses objets pour pas cher, et s'assurer qu'ils se comporteront toujours très exactement comme on le voulait.
Pour finir, une excellente nouvelle : c'est qu'il existe dans VB un petit outil qui vous évitera de frapper vous-mêmes ce code fastidieux. Il suffit pour cela d'aller dans le menu Outils - Gestionnaire de compléments, et de cocher la case "VB Class Builder Utility". Cela rendra ensuite disponible, dans ce même menu Outils, la commande Générateur de Classes.
Grâce à celle-ci, vous pouvez définir en deux clics le nom et le type de chacune des propriétés souhaitées pour une classe de votre cru, et VB se chargera lui-même d'écrire toutes les procédures correspondantes. Merci, monsieur VB.
Définir les méthodes de la classe
Définir les propriétés, c'est bien. Mais définir les méthodes, c'est encore mieux, et, coup de chance, ce n'est pas difficile à faire. En fait, à chaque méthode doit correspondre une procédure qui modifie certaines des propriétés de l'objet
.
Nous voulons par exemple créer la méthode Tirer, qui consiste à sortir un jeton du sac pour l'attribuer à tel ou tel joueur. On suppose qu'on a créé la propriété Emplacement des jetons, propriété numérique qui désigne le numéro du joueur possédant actuellement le jeton (comme au Scrabble il n'y a que quatre joueurs au maximum, on pourrait alors supposer que la valeur 5 désigne un jeton encore dans le sac et la valeur 6 un jeton posé sur le plateau de jeu).
Pour fonctionner, la méthode Tirer aura besoin d'un argument, qui sera le numéro du joueur qui vient de tirer ledit jeton.
Au total, le code donnera :
Public Sub Tirer (Toto As Object, Nb As Byte)
Toto.Emplacement = Nb
End Property
On remarque qu'un argument obligatoire d'une procédure de méthode est l'objet auquel s'applique la méthode. Et si, comme c'est le cas ici, la méthode exige de surcroît des arguments, ces arguments se traduisent par des paramètres supplémentaires de la procédure définissant la méthode.
Toujours est-il qu'une fois ceci fait, dans le corps même de l'application, le tirage du caramel numéro i par le joueur numéro j pourra du coup s'écrire :
Caramel(i).Tirer (j)
Créer des instances de classe Il ne nous reste plus qu'à voir comment le programme peut lui même générer de nouveaux objets (ou en supprimer) en cours de route. En fait, ce n'est là que l'extension aux objets "faits main". d'un procédé déjà largement abordé à propos de objets préfabriqués que sont les contrôles (voir partie 10).
De même que la création d'une variable s'effectue grâce aux mots-clés Dim et As, la création d'un nouvel objet va elle aussi emprunter les mêmes chemins :
Dim Toto As New Jeton
Ici, Toto est le nom (propriété Name) de l'objet, et Jeton correspond obligatoirement au nom d'un module de classe (ou alors, il s'agit d'une classe de contrôles, comme Form, CommandButton, etc.) Si l'on voulait créer dynamiquement les 95 jetons du jeu, le plus simple serait sans doute de dire :
For i = 0 to 94
Dim Caramel(i) As New Jeton
Next i
Et le tour serait joué.
Quant à la destruction d'un objet, elle est d'une simplicité biblique ::
Set Toto = Nothing
Et l'objet disparaît. |