0

Inyección de Dependencias en CRIAX-SDK II

25Jun
en CRIAX-SDK, Documentación, Herramientas, Javascript, SDK, Tutoriales, XUL


Tomo como plantilla para redactar este post y otros sobre el mismo tema, del libro Desarrollo ágil con Symfony 2.1 de Javier Eguiluz. Específicamente el Apendice B: Inyección de Dependencias (pag 577).

En el post anterior se puedo apreciar como en la plataforma CRIAX-SDK, se hace uso de la Inyección de Dependencias.

3. El contenedor de Inyección de Dependencias

Cuando el código de una aplicación es tan sencillo como el mostrado en el post anterior anteriormente, es fácil recordar las dependencias entre clases. Cuando quieras utilizar el Logger, seguramente recordarás que antes debes crear un objeto de tipo File.

El problema es que en las aplicaciones reales existen docenas de estos objetos principales. Entre todos ellos suman cientos de dependencias cruzadas y cientos de opciones de configuración. Manejar todas estas dependencias a mano es simplemente imposible.

Un contenedor de inyección de dependencias es un objeto que sabe cómo crear los objetos de tu aplicación. Para ello, conoce todas las relaciones entre tus clases y las configuración necesaria para instanciar correctamente cada clase.

Siguiendo con el ejemplo anterior, este podría ser un contenedor muy sencillo capaz de crear objetos de tipo Logger:

 var File = inyeccion.model.File;
 var AppPath = criax.chromeless.lib.AppPath;
 var Path = criax.chromeless.lib.Path;
 var Logger = inyeccion.model.Logger;

 /**
  * Modelo para el contenedor
  *
  * @class Container
  * @public
  * @extends qx.criax.domain.DomainModel
  * @author Nilmar Sanchez Muguercia
  * @namespace inyeccion.model
  * @copyrigth
  * @license
  * @version 0.0.1
  *
  */

qx.Class.define("inyeccion.model.Container",
{
    extend : criax.domain.DomainModel,

    /**
     * @property
     */
    properties :
    {

    },

    /**
     * metodo de inicializacion de la clase
     *
     * @constructor
     * @public
     * @param params {array}: arreglo de parametros iniciales
     *
     */

    construct : function(params)
    {
        this.base(arguments);
    },

   /**
     * @method
     */
    members :
    {
        /**
         *  metodo para devolver el objeto File que sera el manejador
         *  de los logs
         *
         * @method getManager
         * @public
         * @param
         * @return
         *
         */

        getManager : function(){
        	var appPath = new AppPath();
		    //archivo de logs en el directorio drecursos
		    var resorcePath = appPath.getResourceDir();
		    var path = new Path(resorcePath);
		    var logFilePath = path.join("logs.txt");

            return new File([logFilePath]);
        },

        /**
         *  metodo para devolver el objeto logger
         *
         * @method getLogger
         * @public
         * @param
         * @return
         *
         */

        getLogger : function(){
        	var manager = this.getManager();
            var logger = new Logger();
            logger.setManager(manager);
            return logger;
        }
    }
});

Haciendo uso del contenedor, puedes simplificar el código de tu aplicación a lo siguiente:

var container = new inyeccion.model.Container();
var logger = container.getLogger();
logger.info("Mensaje de informacion");
logger.error("Mensaje de error");

Ahora tu aplicación simplemente pide un logger al contenedor de dependencias, sin preocuparse de cómo se crea o las clases que hay que instanciar y configurar previamente.

El problema del contenedor anterior es que de nuevo no se puede modificar con facilidad su comportamiento. Refactoriza su código para que mantenga la flexibilidad de la inyección de dependencias
pero con la facilidad de uso que aporta un contenedor:

 var Logger = inyeccion.model.Logger;

 /**
  * Modelo para el contenedor
  *
  * @class Container
  * @public
  * @extends qx.criax.domain.DomainModel
  * @author Nilmar Sanchez Muguercia
  * @namespace inyeccion.model
  * @copyrigth
  * @license
  * @version 0.0.1
  *
  */

qx.Class.define("inyeccion.model.Container",
{
    extend : criax.domain.DomainModel,

    /**
     * @property
     */
    properties :
    {
        /**
         * propiedad para las opciones de configuracion del contenedor
         *
         * @name _options
         * @protected
         *
         */
        _options : {}
    },

    /**
     * metodo de inicializacion de la clase
     *
     * @constructor
     * @public
     * @param params {array}: arreglo de parametros iniciales
     *        params[0]: {type:"",path:"",clazz:function}
     *
     */

    construct : function(params)
    {
        this.base(arguments);

        this._options = params[0];
    },

   /**
     * @method
     */
    members :
    {
        /**
         *  metodo para devolver el objeto File que sera el manejador
         *  de los logs
         *
         * @method getManager
         * @public
         * @param
         * @return
         *
         */

        getManager : function(){
        	switch(this._options.type){
        		case "archivo":
        			var clazz = this._options.clazz;
        			return new clazz([this._options.path]);
        		break;

        		default:
        			return;
        		break;
        	}
        },

        /**
         *  metodo para devolver el objeto logger
         *
         * @method getLogger
         * @public
         * @param
         * @return
         *
         */

        getLogger : function(){
        	var manager = this.getManager();
            var logger = new Logger();
            logger.setManager(manager);
            return logger;
        }
    }
});

Gracias a las opciones añadidas en el contenedor, ya puedes volver a modificar el comportamiento del logger. El propio nombre de la clase es una opción del contenedor. La gran ventaja es que tu código sólo debe pasar un objeto de opciones al contenedor:

var appPath = new AppPath();
//archivo de logs en el directorio drecursos
var resorcePath = appPath.getResourceDir();
var path = new Path(resorcePath);
var logFilePath = path.join("logs.txt");
//opciones
var options = {
    type: "archivo",
    clazz: inyeccion.model.File,
    path: logFilePath
};

var container = new inyeccion.model.Container([options]);
var logger = container.getLogger();
logger.info("Mensaje de informacion");
logger.error("Mensaje de error");

Utilizar un contenedor simplifica mucho el uso de la inyección de dependencias en tu aplicación. El problema es que crear un contenedor con cientos de dependencias es una tarea titánica. Por eso
CRIAX-SDK incluye un completo contenedor de inyección de dependencias listo para usar.

4. El contenedor de Inyección de Dependencias de CRIAX-SDK

Lo primero es obtener una instancia de la clase singleton criax.dic.DiContainer. Luego crearemos cada una de las dependencias iniciales y a manera de identificador pasamos una cadena de forma tal que cada una sea única. De esta manera ya no tendremos que crear un método por cada dependencia que deseemos obtener simplemente con un método generico y pasándole la cadena identificadora obtendremos la dependencia.

 var Logger = inyeccion.model.Logger;

 /**
  * Modelo para el contenedor
  *
  * @class Container
  * @public
  * @extends qx.criax.domain.DomainModel
  * @author Nilmar Sanchez Muguercia
  * @namespace inyeccion.model
  * @copyrigth
  * @license
  * @version 0.0.1
  *
  */

qx.Class.define("inyeccion.model.Container",
{
    extend : criax.domain.DomainModel,

    /**
     * @property
     */
    properties :
    {
        /**
         * contenedor de inyección de dependencias de CRIAX-SDK
         *
         * @name __container
         * @private
         *
         */
        __container : {}
    },

    /**
     * metodo de inicializacion de la clase
     *
     * @constructor
     * @public
     * @param params {array}: arreglo de parametros iniciales
     *        params[0]: {type:"",path:"",clazz:function}
     *
     */

    construct : function(params)
    {
        this.base(arguments);

    },

   /**
     * @method
     */
    members :
    {
        /**
         *  metodo para devolver la inyeccion configurada
         *
         * @method getInyection
         * @public
         * @param key {String}: identificador de la inyeccion
         * @return
         *
         */

        getInyection : function(key){
        	return this.__container.get(key);
        },

        /**
         *  metodo para configurar las inyecciones
         *
         * @method configInyections
         * @public
         * @param options {Object}: obciones de configuracion
         * @return
         *
         */

        configInyections : function(options){
        	this.__container = criax.dic.DiContainer.getInstance();
        	var manager = {};

      		switch(options.type){
        		case "archivo":
        			var clazz = options.clazz;
        			manager = new clazz([options.path]);
        		break;

        		default:
        			return;
        		break;
        	}

        	this.__container.set("log_manager",manager);

      		var logger = new inyeccion.model.Logger();
      		//optener la inyeccion del manjador de logs
      		logger.setManager(this.__container.get("log_manager"));
      		this.__container.set("loggers",logger);
        }
    }
});

En el Application.js

var appPath = new AppPath();
//archivo de logs en el directorio drecursos
var resorcePath = appPath.getResourceDir();
var path = new Path(resorcePath);
var logFilePath = path.join("logs.txt");

//opciones
var options = {
  type: "archivo",
  clazz: inyeccion.model.File,
  path: logFilePath
};

var container = new inyeccion.model.Container();
container.configInyections(options);
var logger = container.getInyection("loggers");

logger.info("Mensaje de informacion");
logger.error("Mensaje de error");

Aún de esta manera configurar todas las inyecciones de dependencias de una aplicación es una tarea bastante tediosa, pero como siempre puede ser mejorada, para ello se definen servicios en el contenedor, sólo tienes que crear una clase y añadir unas pocas líneas en un archivo de configuración JSON. CRIAX transforma automáticamente esa configuración en el código JS que realmente se ejecuta para instanciar dependencias, cargar opciones de configuración y crear los objetos solicitados por tu código.

En el proximo post veremos como se lleva a cabo esta labor.


Source de la aplicación: solo crear un proyecto llamado inyeccion y sustituir el directorio source, por el adjunto descompactado.

Source

0 MB

Dejar un comentario

¿Eres humano? Entonces resuelve esta operación: * Límite de tiempo se agote. Por favor, recargar el CAPTCHA por favor.