Salut tout le monde !
Ayant regardé la très bonne vidéo sur le design pattern relatif au DIC, j'ai eu la folle idée de recréer ce système en JavaScript. Je me suis heurté à plusieurs problèmes :
J'ai la bonne nouvelle de vous annoncer que j'ai plus ou moins réussi à contourner ces problèmes. C'est un petit projet qui m'a demandé quelques recherches. Beaucoup de fonctions de facilité qui existent en PHP n'existent tout simplement pas en JavaScript (du style newInstanceArgs ou encore getParameters).
Avant de vous présenter le script, je vais directement vous présenter le résultat du script. Celui-ci est très puissant couplé à système comme browserify qui permet de s'affranchir des limitations de chargement asynchrone de code. (on peut utiliser d'autres systèmes bien entendu comme require.js).
var DIC = require("./core/DIC.js");
var app = new DIC();
window.Foo = function Foo() {}
// Bar dépend de Foo
window.Bar = function Bar(Foo) { }
console.log(app.get('Bar'));
paramètres par défaut
Si vous avez des paramètres qui ont une valeur par défaut, une valeur null sera envoyée. Il est donc très facile d'initialiser vos paramètres qui ne sont pas des classes :
window.Bar = function Bar(Foo, param)
{
this.param = param || "chien";
}
Limitations du système
window.NomDeClasse = function NomDeClasse(Parametres)
{
}
Voici le script :
/**
* Conteneur d'injection de dépendances avec réflexion de code
* @class DIC
* @constructor
**/
var DIC = function()
{
"use strict";
/**
* Contient la liste des callback d'une classe nommée par un alias
* @propery registry {Array}
* @default empty array
**/
this.registry = new Array();
/**
* Contient la liste des instances d'une classe nommée par un alias
* @propery instances {Array}
* @default empty array
**/
this.instances = new Array();
/**
* Contient la liste des recettes d'instances d'une classe nommée par un alias
* @propery factories {Array}
* @default empty array
**/
this.factories = new Array();
/**
* Permet d'enregistrer une classe dans le registre avec son alias et un callback qui permet de savoir comment instancier cette classe
* @method set
* @param alias {String} L'alias de la classe
* @param callback {Function} La fonction d'instanciation de la classe
* @return {void}
**/
this.set = function(alias, callback)
{
this.registry[alias] = callback;
};
/**
* Permet d'enregistrer de manière unique une classe dans le registre avec son alias et un callback qui permet de savoir comment instancier cette classe
* @method setFactory
* @param alias {String} L'alias de la classe
* @param callback {Function} La fonction d'instanciation de la classe
* @return {void}
**/
this.setFactory = function(alias, callback)
{
this.factories[alias] = callback;
};
/**
* Permet d'ajouter l'instance d'une classe au DIC
* @method setInstance
* @return {void}
**/
this.setInstance = function(instance)
{
var alias = instance.constructor.name;
this.instances[alias] = instance;
};
/**
* Permet d'accéder à l'instance ou la définition d'une classe par son alias
* @method get
* @param alias {String} L'alias de la classe à accéder
* @return {Function}
**/
this.get = function(alias)
{
if(this.factories[alias])
return this.factories[alias]();
if(!this.instances[alias])
{
if(this.registry[alias])
this.instances[alias] = this.registry[alias]();
else
{
if(window[alias])
{
this.instances[alias] = new window[alias]();
var args = this._getArguments(alias);
for(var i = 0; i < args.length; i++) {
if(window[args[i]])
args[i] = this.get(args[i]);
else
args[i] = null;
}
for(var i = 0; i < args.length; i++)
if(args[i])
this.instances[alias][args[i].constructor.name] = args[i];
}
else
throw new Error("Can't resolve class " + alias);
}
}
return this.instances[alias];
};
/**
* Permet de connaitre le nom des paramètres d'une classe
* @method _getArguments
* @param alias {String} L'alias de la classe à accéder
* @return {Array}
**/
this._getArguments = function(alias)
{
var str = window[alias].toString();
str = str.split('{')[0].split('(')[1].split(')')[0].split(',');
for(var s in str)
str[s] = str[s].trim(' ');
return str;
};
};
En éspérant que cela serve à d'autres !