Inyección de Dependencia con Spring.Net

Spring.Net es uno de los frameworks más conocidos para implementar Inyección de Dependencia (también conocido como Inversión de Control -IoC). Otros que nos permiten hacer este trabajo son: PicoContainer, ObjectBuilder, Windsor Container.

Basicamente, qué queremos lograr? Fácil, crear nuestros objetos, sin importar quién me provea la implementación.

En vez de hacer esto:

(1) Cliente obj_cliente = new Cliente();

Podemos hacer esto:

(2) ICliente obj_cliente = (ICliente) AppContext.Instance.GetObject("Cliente");

Expliquemos, en (1) le estamos diciendo a obj_cliente quién va a crearlo: new Cliente(); Es decir, le estamos diciendo quien le va a proveer de la implementación, y nunca vamos a poder cambiar esto, a menos que lo hagamos y volvamos a compilar. En (2) es distinto, estamos pidiendo una implementación, pero no sabemos quien nos la va a dar. Solo sabemos que quién nos proveea la construcción, va a implementar la interfaz ICliente. AppContext es un wrapper que hice para crear un singleton del contexto de toda la aplicación (está en el codigo fuente que se puede descargar más abajo).

El lugar donde le decimos qué clase se va a encargar de la implementación, es en el app.config (en una de las tantas lineas para configurar Spring.Net):

<object name=»Cliente» type=»Entities.Cliente, Entities» singleton=»false»/>

En esta línea de código Entities.Cliente es la Clase que nos proveerá la implementación, y Entities es el assembly (que TIENE que estar en la carpeta de salida, donde está el .exe). También podemos ver cuan fácil es implementar un singleton de esta manera, solamente escribiendo singleton=»true» (ú obviandolo, es el valor por defecto), entonces no tenemos que hacerlo programaticamente.

Para el ejemplo lo que hice es organizar los proyectos de esta forma:

Lo que hariamos normalmente es referenciar Entities desde todas las partes del proyecto, en vez de esto, lo haremos con Entities.Contracts que contienen las interfaces, de modo que siempre programaremos contra las interfaces, nunca contra la implementación. Los proyectos no poseen relación de conocimiento con Entities, en ningún momento se lo referencia.

El tip del día: Hay que programar contra las interfaces.

Descargar codigo fuente [Proyecto hecho con SharpDevelop]

Donde más podemos utilizarlo ? En la capa de acceso a datos, podríamos persistir los objetos con db4o, y en otra implementación lo podríamos hacer usando NHibernate! Y esto lo lograríamos creando una interfaz IBaseRepository que tenga metodos como Guardar, Eliminar, Buscar y luego crear las implementaciones para cada uno de los providers por ejemplo BaseRepositoryDb4o y BaseRepositoryNH.

Espero que sirva!

10 comments so far

  1. Emilio Velardiez on

    Hola,

    Cuando desarrollas con este tipo de fmks AOP que proporciona la reflexion pierdes la productividad que otorga el Intellisense del ensamblado que reflexionas?

    Saludos.

  2. GLM on

    Cual es la mayor diferencia…

    Estoy hablando nada mas y nada menos de Activator.CreateInstance(assembly, type);

    o sea lo que veo es que Spring.net va a buscar el solo un objeto (¿Cualkiera?) que implemente ICliente y te lo tira… es algo un poco menos especifico que CreateInstance…

    Recientemente estuve viendo el codigo de un plug in del Reflector de Lutz… y miraba como implementaba la conexion con la aplicacion host, es un tipico ejemplo ya que habia una linea: Reflector.ILoQueSea = this.plugInContext.GetLoQueSea();
    (no era lo que sea, sino una de las tantas interfaces que expone Reflector, pero no es lo importante)
    Dario, Podriamos usar este tipo de cosas para implementar un soporte de plugins? Hablando de plugins los nuevos aplication blocks traen un block para esto
    Muy buen post!

    Saludos

  3. GLM on

    Emilio: evidentemente al hacer una instanciacion de un objeto que no lo tiene referenciado, pierde el intellisense del objeto en si (porque la referencia no esta en el proyecto), pero Dario deberia tener la interface ICliente bien conocida (referenciada) en su proyecto, por lo que el trata en la aplicacion al objeto como un ICliente, y tiene intellisense de ICliente.
    Podes pensarlo, si se te hace mas facil, como que ICliente es una clase base, y por lo tanto tenes acceso al intellisense. De hecho es valido usar una clase base para este tipo de escenarios, pero no estoy seguro si Spring.Net lo soporta.

    Saludos

  4. Dario Quintana on

    Emilio, GLM respondió por mí. Al usar la interfaz ICliente, usas el intellisense sin problemas, que es un accidente de que se puedan ocupar los metodos, sino no tenés cómo trabajar con los métodos/properties/fields de Cliente.

    Ahora bien, cual es la mayor diferencia entre Activator.CreateInstance(assembly,type) y lo que está haciendo Spring en el ejemplo ? CreateInstance es una función y Spring es un feroz framework 🙂 ahora… hablando solamente de la instanciación…ninguna. Convengamos que la inyección por Spring te dá mucho vuelo (es un framework no?), con solo poner singleton=true ténes el singletón cocinado. Aparte la instanciación se está realizando para un contexto, que en otra app, el contexto puede es otro y puede q cambiar la implementación…y esto se complica programandolo sin un framework q te ayude.

    Con respecto a los plugins…esto es lo que se usa, no tenés otra (q yo conozca). Cambiarle las palabras/framework/helper hechos por nosotros, pero tarde o temprano tenes que usar estos principios.

    Y como nombraba entre todos los containers que te permiten hacer IoC el ObjectBuilder es escrito por los muchachos de Patterns and Practices y es lo que se ocupa en los App Blocks (el link está al comienzo del post)

    Que opinan ?

  5. Emilio Velardiez on

    Hola Dario,

    Hasta donde yo se de POO el uso de Interfaces tienen que ver con la descripción de comportamientos, como ejemplos ISerializable o IDataBound. Creo que el uso que hacemos de «ICliente» se aproxima más a la de una clase abstracta y no a la de una Interfaz. No se que opináis al respecto?

    Saludos.

  6. Dario Quintana on

    Es cierto, con interfaces hablamos sobre la descripción de comportamientos y es justamente los que necesitamos, por eso las usamos. Debemos saber exactamente que tiene que hacer alguien implemente una interfaz, sin importar como lo haga.

    Tiene sus diferencias el hablar de clases Abstractas e Interfaces, aunque en algunos ambientes no importe que usemos.

    El tema aquí es que nosotros estamos estableciendo un compromiso contractual entre las clases que quieran implementar ICliente, de modo que sí o sí debemos dar una implementación de todos los methods/properties en las clases que heredan/implementan de ICliente.
    En una clase abstracta, no se dá esto, es decir, puedo en una clase derivada de AbstractCliente, no implementar un metodo ó una propiedad y optar hacerlo en una proxima derivada.
    Otra cosa importante, es que al hablar de una clase abstracta (si bien no se puede instanciar) ya estamos hablando de una implementación, que puede ser mínima o no, y esto es justamente lo que estamos queriendo desacoplar, la implementación. Podría ser válido tener una clase AbstractCliente que implementa ICliente, y despues podríamos hacer que Cliente herede de AbstractCliente, pero en mi opinión no creo que justifique el esfuerzo, no creo que haya mucho que escribir en AbstractCliente.

    Por cierto, muy buenos los comentarios!
    Saludos

  7. Indirect on

    Somehow i missed the point. Probably lost in translation 🙂 Anyway … nice blog to visit.

    cheers, Indirect!

  8. Raul on

    Hola, Probe el ejemplo y funciona. Pero cuando le hago una modificación deja de funcionar. Por ejemplo, probe agragar un objeto Cliente2 igual a cliente y no funciona. Con solo agregar este Cliente2 debajo de objeto Cliente en la configuración tira una Exeption. También probe renombrando a Cliente, como objeto único y no anda tampoco. No entiendo que sucede con este ejemplo.

  9. Felipe on

    Hola!… efectívamente el código funciona pero, tal y como lo menciona el post anterior, genera un exception al intentar rediguir el objeto inyectado a uno alternativo que tambien implementa la interfaz (en este caso una copia de Cliente con otro nombre)… Darío, ¿podrías explicar cómo configurarlo para utilizar otro objeto que es el fin último de esto?

    Saludos,

    Felipe

  10. Kabymur on

    Alguien me puede indicar como instalar el Spring .net en el computador, he buscado todo el día info y no aparece ni como instalarlo ni como referenciarlo.

    Gracias


Replica a Felipe Cancelar la respuesta