WinDev et le Design pattern : singleton

Design pattern de création : Singleton

WinDev est un EDI édité par la société française PC-Soft et conçu pour développer des applications. Il propose son propre langage appelé le WinDev. Celui-ci facilite le travail du développeur :

  • gestion des événements simplifiée ;
  • fonctions W-langage complètes pour la programmation courante ;
  • réalisation rapide d'interfaces graphiques élégantes.

Cette facilité apportée par WinDev ne doit pas empêcher de structurer un projet et de mettre en place une analyse de conception, en d'autres termes ne pas foncer tête baissée en enquillant les lignes de code. Dans une série d'articles, je vais appliquer les design patterns à WinDev. En premier, nous allons étudier le design pattern de création : singleton.

12 commentaires Donner une note à l'article (4.5)

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Qu'est-ce qu'un design pattern

Depuis les débuts de la programmation, les développeurs ont rencontré différents problèmes de conception. La plupart de ces problèmes sont récurrents. Pour éviter aux autres développeurs de buter sur les mêmes soucis, certains groupes de développeurs ont développé ce qu'on appelle des design patterns (ou patrons de conception en français). Un design pattern est une solution à un problème récurrent dans la conception d'applications orientées objet. Il décrit alors une solution standard, utilisable dans la conception de logiciel.

II. Le Design Pattern : Singleton

II-A. Description du problème

Un grand nombre d'applications possèdent des classes qui doivent (ou peuvent) être instanciées une seule et unique fois :

  • connexion à une BDD ;
  • gestion des fichiers de journalisation ;
  • lecture d'un fichier INI ;
  • récupération de paramètres généraux.

Par exemple, instancier plusieurs fois une classe lisant un fichier de configuration n'a aucun intérêt. Alors, la question est : « comment instancier une seule fois une classe utilisée plusieurs fois ?» La solution fréquemment adoptée est la gestion d'une variable globale au lancement du programme. Cette solution est à éviter pour les raisons suivantes :

  • respect de l'encapsulation ;
  • éviter aux développeurs de créer une autre instance ;
  • ne pas multiplier les variables globales dont le chargement au départ aura un impact sur les performances de l'application ;
  • maintenance ingérable en cas de multiplications de variables et de travail en équipe.

Le design pattern Singleton répond à l'ensemble de ces problèmes.

II-B. La solution

La solution que nous allons mettre en place devra :

  1. permettre au développeur de récupérer l'instance de l'objet (instanciation à la demande) ;
  2. empêcher le développeur de créer une nouvelle instance ;
  3. contrôler le nombre d'instances.

III. Programmation du design Pattern

Passons à la pratique. Nous allons créer une classe pc_bdd qui gère la connexion à une base de données (BDD). Pour cet exemple, la classe sera composée d'un seul attribut lo_bdd de type pc_bdd.

III-A. Récupérer l'instance

Déclaration de la classe pc_bdd
Sélectionnez
1.
2.
3.
4.
pc_bdd est une Classe
PRIVÉE GLOBALE     
    lo_bdd est un pc_bdd dynamique
FIN
Procédure Get instance pour récupérer l'instance
Sélectionnez
1.
2.
PROCEDURE GLOBALE GetInstance()
RENVOYER ::lo_bdd

Nous venons de mettre en place la classe avec la fonction GetInstance() qui permet au développeur de récupérer l'instance de la classe. L'attribut lo_bdd est privé pour forcer le programmeur à utiliser la procédure GetInstance(). Comme celle-ci est globale (statique), lo_bdd est global (statique) par la même occasion.

Rappel : Une procédure globale (statique) ne peut manipuler que des variables globales (statiques).

Ne pas confondre le type global (statique) d'une méthode de classe et de ses membres et l'avantage du singleton d'éviter la multiplication de variables globales au projet qui se chargent au lancement du programme.

III-B. Interdire une nouvelle instance

Pour empêcher les développeurs d'instancier un objet, nous allons déclarer son constructeur en privé

Constructeur privé
Sélectionnez
1.
2.
PROCEDURE PRIVÉE Constructeur()
// À cet endroit on peut y insérer le code de connexion

Le constructeur déclaré dans cet exemple ne contient pas de code, libre à vous d'y insérer votre code de connexion à votre BDD.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
// Connexion à une base MySQL en utilisant un driver JDBC :
SQLConnecte("jdbc:mysql://" + monServeur + "/" + madatabase,"moi", "monpwd", "", "JDBC", "com.mysql.jdbc.Driver")

// Connexion en utilisant une source de données ODBC : 
SQLConnecte("jdbc:odbc:MaSource", "moi", "monpwd", "", "JDBC", "sun.jdbc.odbc.JdbcOdbcDriver")

// Connexion en utilisant HyperFileSQL : 
SQLConnecte("MonAnalyse.WDD", "", "monpwd", "", "HyperFileSQL")

III-C. Contrôler le nombre d'instances

Pour contrôler le nombre d'instances, nous allons intervenir sur la procédure GetInstance() en y ajoutant un test. Le test consiste à comparer notre attribut à Null et créer une instance le cas échéant.

Procédure GetInstance avec le contrôle d'instanciation
Sélectionnez
1.
2.
3.
4.
5.
PROCEDURE GLOBALE GetInstance()
SI ::lo_bdd=Null ALORS
    ::lo_bdd=allouer un pc_bdd()
FIN
RENVOYER ::lo_bdd

III-D. Exemple d'utilisation

Dans ce paragraphe, nous allons voir le code d'utilisation de cette classe.

Exemple de code
Sélectionnez
1.
lo_bdd est un pc_bdd dynamique=pc_bdd::GetInstance()

III-E. Encore un effort et c'est bon…

Nous venons de programmer une classe selon le design pattern singleton, mais dans la démarche intellectuelle, nous sommes partis du principe que la procédure GetInstance() n'est jamais exécutée plusieurs fois en même temps. En effet, nous n'avons pas pris en compte les logiciels multithread. En l'état actuel, dans le cas d'un programme multithread, on peut se retrouver avec plusieurs instances de pc_bdd. Comment est-ce possible ? L'origine du problème est l'exécution en parallèle des processus, deux processus exécutent en même temps la procédure GetInstance(), et constatent que l'attribut lo_bdd est Null, ils vont donc créer chacun une instance. L'astuce consiste à permettre une seule exécution par un seul processus. Pour cela, WinDev dispose des fonctions : SectionCritiqueDébut() et SectionCritiqueFin() pour encadrer le code à bloquer.

Nous allons effectuer ce blocage dans la procédure GetInstance() pour ne pas impacter les développeurs.

GetInstance avec le blocage multiThread
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
PROCEDURE GLOBALE GetInstance()
SectionCritiqueDébut()
SI ::lo_bdd=Null ALORS
    ::lo_bdd=allouer un pc_bdd()
FIN
SectionCritiqueFin()
RENVOYER ::lo_bdd

IV. Conclusion

Cet article explique les avantages et l'implémentation du design pattern « Singleton » dans WinDev. Mais celui-ci ne fait pas l'unanimité en programmation, il est souvent qualifié d'antipattern, car il est difficilement testable, souvent mal utilisé et empêche l'évolutivité d'une application. Il est souvent utilisé pour regrouper des variables globales dans une classe.

Remerciements :

  • relecture technique : littlewhite ;
  • relecture orthographique : ced ;
  • vérification avant mise en ligne : djibril

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 v. Formet - Dsr57. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.