Ce bref texte se veut un exemple de rédaction d'un singleton simple en JavaScript. Notre singleton de démonstration sera un générateur d'identifiants uniques, par souci de simplicité. Pour des détails sur le schéma de conception singleton en tant que tel, ou pour des comparatifs avec des exemples de la même pratique dans d'autres langages, référez-vous à ../Developpement/Schemas-conception.html#singleton
Donnons d'office le code tout entier, que nous analyserons par la suite élément par élément :
var GénérateurId = (function () {
var instance;
function ZeGénérateur() {
this.cur = 0;
this.prochain = function () {
return this.cur++;
};
}
function createInstance() {
var singleton = new ZeGénérateur();
return singleton;
}
return {
getInstance : function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function testGénérerIdentifiant() {
document.getElementById("identifiantGénéré").innerHTML = "<strong>" + GénérateurId.getInstance().prochain() + "</strong>";
}
Vous pouvez vous convaincre que le tout fonctionne en appuyant à quelques reprises sur le bouton ci-dessous et en constatant que l'identifiant généré change chaque fois, suivant une croissance monotone.
Les éléments clés de l'implémentation de ce singleton vont comme suit. Nous prendrons d'abord une vue d'ensemble, quelque peu aérienne, puis nous comblerons les « trous » en insérant progressivement les éléments de code qui permettront de mieux saisir cette pratique dans le détail.
Vu de haut, l'idée maîtresse de cette implémentation est que le singleton, associé à la variable GénérateurId, est un « objet » résultant de l'exécution d'une fonction qui est créée de manière anonyme pour les besoins de la cause. On peut constater cela du fait que la fonction est créée entre deux parenthèses, puis que le résultat de cette création anonyme est appelé (paire de parenthèses suivant la déclaration de la fonction) de manière à retourner ce qui servira de singleton en pratique. À l'utilisation, par la suite, on accède au singleton en appelant la méthode getInstance() de GénérateurId. Cette méthode s'assure que le véritable objet ne sera effectivement créé qu'une seule fois. Le singleton, en pratique, n'est pas vraiment GénérateurId mais est plutôt un « objet » caché à l'intérieur de GénérateurId, et qui n'est exposé qu'en passant à travers le service getInstance(). Dans notre cas, cet « objet caché » est une instance de ZeGénérateur; nous y reviendrons plus bas. |
|
La mécanique d'instanciation du singleton s'exprime en trois étapes :
|
|
Enfin, l'« objet » qui ne sera instancié qu'une seule fois sera un ZeGénérateur. Dans notre cas, cet objet aura un attribut (cur) et une méthode (prochain), la méthode ayant pour rôle de retourner à chaque appel un identifiant distinct. Notez que dans cette implémentation, l'attribut et la méthode sont tous deux publics, ce qui est souhaitable dans le cas de la méthode mais l'est moins dans le cas de l'attribut. À votre avis, pourrait-on faire mieux? |
|