Edit du 03/05/2018 : suite à une remarque pertinente de @Jack sur les propriétés et sur les objets, je modifie un peu le texte.

Introduction

Voici le troisième article sur la POO avec WinDev®. Si vous ne les avez pas lu, je vous invite à lire les précédents (article n°1 et article 2).

Dans les articles précédents, je vous expliquais pourquoi on utilisait la POO. Aujourd'hui, je vais vous expliquer le comment. Nous allons voir comment créer une classe, et surtout, comment elle est structurée. J'insiste encore une fois, la POO est intéressante si vous maîtrisez le pourquoi et le comment. Si vous ne comprenez qu'une des deux notions, vous allez semer le chaos dans vos projets. C'est du vécu...

Enfin, la présentation que je vais vous faire va être très générale. Je ne vais pas rentrer tout de suite dans les détails. Donc, pour les connaisseurs, sachez que je ne vais pas parler des cas particuliers aujourd'hui. Ce sera pour une prochaine fois.

Les classes

Lorsqu'on utilise la POO, on crée et on manipule des objets. La création se fait au moyen d'un outil que l'on appelle classe. Il faut considérer une classe comme un moule que l'on peut utiliser à volonté pour créer autant d'objets que l'on souhaite. Si l'on souhaite un autre genre d'objet, on utilise un autre moule. Je vais maintenant vous décrire la composition d'une classe.

Parlez-vous "objet" ?

Avant d'aller plus loin, il est bon d'intégrer quelques notions de vocabulaire.

Les objets (ou instances de classe)

Un objet (que l'on appelle aussi instance de classe) est une entité placée en mémoire qui a été créée à partir du moule qu'est une classe. Chaque objet a une identité propre et plusieurs objets issus de la même classe peuvent co-exister en même temps.

Les membres (ou attributs) d'une classe

De manière générale, lorsqu'on vous parle d'un membre d'une classe, on vous parle d'une variable. Cette variable est particulière car elle est liée à l'objet. Cela veut dire que deux objets différents ont chacun une variable différente. Pour vous donner un exemple, imaginez que vous avez deux fenêtres WinDev. Chacune a une propriété ..Hauteur différente. ..Hauteur est donc l'équivalent d'un membre.

Les membres ont des caractéristiques que nous verrons une prochaine fois.

Les méthodes

Si les membres sont des variables, alors les méthodes sont des procédures ou des fonctions. Une chose les distingues des procédures / fonctions dont vous avez l'habitude. Elles ont un accès direct aux membres ainsi qu'à l'instance de la classe elle-même.

Les méthodes ont elles aussi des caractéristiques que nous étudierons plus tard.

Dans une classe, on distingue deux méthodes particulières :

Le constructeur

Le constructeur est une méthode particulière qui permet d'initialiser l'objet, donc ses membres. Il accepte des paramètres comme n'importe quelle méthode. Par contre, il ne peut pas retourner de valeur (on considère de manière implicite qu'il renvoie l'objet créé). Il faut noter que le constructeur est forcément appelé à la création d'un objet.

Le destructeur

C'est la seconde méthode particulière que vous croiserez mais que vous n'utiliserez presque jamais. Elle est appelée lorsque l'objet est détruit et permet de libérer les ressources maintenues par l'objet. Pour des raisons techniques que vous verrez certainement dans les commentaires ou dans mon 10eme article sur la POO, on ne sait pas forcément à quel moment le destructeur va être appelé. C'est pourquoi je vous déconseille de l'utiliser sans savoir ce que vous faîtes vraiment.

Les propriétés

Pour les novices, les propriétés sont un concept que l'on ne retrouve pas dans le procédural. Vu de l'extérieur, une propriété ressemble à un membre, mais vu de l'intérieur, elle ressemble à une méthode. C'est une notion très intéressante dans la POO.

Bien sûr, vous allez me dire que vous connaissez déjà les propriétés puisque vous en avez certainement déjà manipulé avec les objets de WinDev (..hauteur dont je parlais plus haut par exemple). Mais dans ce cas, faîtes-vous réellement la différence entre une propriété et un membre ? Vous verrez la différence un peu plus loin dans l'article et vous comprendrez pourquoi c'est inédit (edit : merci @Jack pour cette remarque).

Créer une classe avec WinDev

Dans WinDev, la création d'une classe est toute simple. C'est la même action que créer une collection de procédures sauf que vous choisissez Classe à la place (pour les novices, dans WinDev 22, vous faîtes Ctrl + N / Code / Classe).

Et voilà, vous vous retrouvez avec une jolie classe fraichement créée et vous voyez 3 blocs de code :

Déclaration

Dans ce bloc, vous déclarez les membres de la classe. Pour faire simple, vous les déclarez comme si vous étiez dans la partie Déclaration globale d'une fenêtre ou d'une procédure. Un membre se déclare de la même manière qu'une variable. On peut indiquer une valeur par défaut pour chaque membre dans la partie déclaration, mais je préfère les initialiser explicitement dans le constructeur.

Par exemple, pour avoir une classe avec un membre ma_valeur :

cMaClasse est une Classe
    ma_valeur est une chaine
FIN

Le constructeur

Comme expliqué précédemment, le constructeur permet d'initialiser les membres.

PROCEDURE Constructeur(valeur_initiale est une chaine)
    ma_valeur = valeur_initiale

Afin d'avoir un code propre et optimisé, je vous conseille de n'y mettre que le code d'initialisation des membres. Et faîtes en sorte que l'optimisation soit la plus rapide possible (évitez d'y lire un fichier ou de faire un accès à la base de données par exemple).

Le destructeur

Laissez-le vide pour commencer.

PROCEDURE Destructeur()

Ajouter une méthode

Une méthode se crée comme dans une collection de procédures (pour les novices : F4, indiquez le nom et laissez tout par défaut). Et voilà, une nouvelle méthode. Codez la comme vous coderiez une procédure / fonction et c'est tout.

La seule particularité, c'est que vous avez un accès direct au membre ainsi qu'à l'instance de la classe (l'objet).

Pour accéder aux membres, vous pouvez mettre directement le nom du membre. En fonction du paramétrage de votre projet, vous aurez peut-être l'obligation de précéder le nom du membre avec le symbole deux-points (:).

PROCEDURE ajouter_suffixe(suffixe est une chaine)
ma_valeur = ma_valeur + suffixe

ou

PROCEDURE ajouter_suffixe(suffixe est une chaine)
:ma_valeur = :ma_valeur + suffixe

Pour accéder à l'objet, vous avez à disposition le mot clé objet (faîtes attention, on l'oublie très facilement ce mot). Considérez que c'est l'équivalent de la variable MaFenêtre dans une fenêtre.

PROCEDURE est_égal(autre_objet est un cMaClasse)
    renvoyer objet.ma_valeur = autre_objet.ma_valeur

Créer une propriété

Pour créer une propriété, il faut passer par le menu contextuel (clic droit sur la classe dans l'explorateur de projet puis nouvelle propriété ou clic droit dans le volet code au niveau de la liste des membres et méthodes de la classe).

On vous demande un nom et si vous souhaitez que la propriété soit accessible en lecture et / ou en écriture. Pour les autres paramètres, laissez-les de côté pour le moment.

Comme je vous l'ai dit, une propriété ressemble à une procédure quand on la regarde de l'intérieur. Effectivement, WinDev crée deux blocs de code :

  • Récupération de la propriété (lecture)
  • Affectation de la propriété (écriture)

La présence de code dans un bloc l'active tandis que l'absence le désactive. Cela vous permet d'utiliser un système inédit pour vous si vous n'avez jamais fait de la POO. La possibilité d'avoir des variables qui sont accessibles soit en lecture, soit en écriture, soit les deux.

Par exemple, je peux créer la propriété taille qui fait la chose suivante :

PROCEDURE taille()
    Renvoyer Taille(:ma_valeur)

Je peux lire la taille de mon objet mais je ne peux pas la modifier.

Manipuler une classe

La manipulation d'une classe ressemble un peu à la manipulation d'une structure, sauf que la structure ne propose pas de méthode (sauf si vous avez lu les premiers articles de mon blog).

Un exemple sera plus parlant qu'un long texte :

mon_objet est une cMaClasse("valeur test")
Trace(mon_objet.ma_valeur)

mon_objet.ajouter_suffixe(" fin")
Trace(mon_objet.ma_valeur)

SI mon_objet.taille >= 15 ALORS
    Trace("L'objet a une taille de 15 ou plus")
SINON
    Trace("L'objet a une taille de moins de 15") 

Petites remarques en vrac

Conclusion

Et voilà, vous connaissez les bases de la POO avec WinDev. Je vous ai volontairement caché beaucoup de chose pour avoir un article le plus simple possible. Dans le prochain article, j'aborderai la mise en place du polymorphisme, la partie la plus intéressante à mon avis de la POO.

J'espère que vous prendrez autant de plaisir à lire cet article que moi à l'écrire. Comme je vous l'ai dit pour les précédents, n'hésitez pas à commenter et à critiquer les articles pour que je puisse les améliorer et / ou les corriger. Vous pouvez aussi me poser vos questions, j'essaierai d'y répondre le plus rapidement possible.

Enfin, je vous serai très reconnaissant si vous partagez cet article avec vos collègues ou sur les réseaux sociaux. Plus on est de fous, plus on rit.

Je vous remercie pour votre lecture et je vous dis à très bientôt pour un nouvel article.