2009-05-23 15 views
13

Utilizo la inyección de dependencia a través de parámetros y constructores de manera extensiva. Entiendo el principio en este grado y estoy contento con él. En mis proyectos grandes, termino con demasiadas dependencias que se inyectan (todo lo que alcanza cifras dobles se siente grande, me gusta el término 'código de macarrones').¿Alguien puede explicarme, por mucho tiempo, cómo usar los contenedores de COI?

Como tal, he estado considerando contenedores de COI. He leído algunos artículos sobre ellos y hasta ahora no he podido ver el beneficio. Puedo ver cómo ayuda a enviar grupos de objetos relacionados o a obtener el mismo tipo una y otra vez. No estoy seguro de cómo me podrían ayudar en mis proyectos, donde puedo tener más de cien clases implementando la misma interfaz, y donde las uso todas en diferentes órdenes.

Entonces, ¿alguien puede señalarme algunos buenos artículos que no solo describen los conceptos de contenedores de COI (preferiblemente sin exagerar uno en particular), sino que también muestran en detalle cómo me benefician en este tipo de proyecto y cómo encajan? en el alcance de una gran arquitectura?

Espero ver algunas cosas que no sean específicas del idioma pero mi idioma preferido si es necesario es C#.

Respuesta

1

no tengo vínculos, pero le puede proporcionar un ejemplo:

tiene un controlador web que tiene que llamar a un servicio que tiene una capa de acceso a datos.

Ahora, tomo en su código que está construyendo estos objetos usted mismo en tiempo de compilación. Está utilizando un patrón de diseño decente, pero si alguna vez necesita cambiar la implementación de, digamos, el dao, debe ingresar el código y eliminar el código que establece esta dependencia, recompilar/probar/implementar. Pero si tuviera que usar un contenedor IOC, simplemente cambiaría la clase en la configuración y reiniciaría la aplicación.

3

Si usted tiene más de un centenar de clases que implementan una interfaz común, una COI no le ayudará mucho, necesita una fábrica . esta manera, usted puede hacer lo siguiente:

public interface IMyInterface{ 
    //... 
} 

public class Factory{ 

    public static IMyInterface GetObject(string param){ 
     // param is a parameter that will help the Factory decide what object to return 
     // (that is only an example, there may not be any parameter at all) 
    } 
} 

//... 
// You do not depend on a particular implementation here 
IMyInterface obj = Factory.GetObject("some param"); 

Dentro de la fábrica, es posible utilizar un contenedor IoC para recuperar los objetos si se quiere, pero usted tendrá que registrarse en cada una de las clases que implementan la interfaz dada y asociarlas a algunas claves (y usar esas claves como parámetros en el método GetObject()).

Un COI es particularmente útil cuando se tiene que recuperar objetos que implementan diferentes interfaces:

IMyInteface myObject = Container.GetObject<IMyInterface>(); 
IMyOtherInterface myOtherObject Container.GetObject<IMyOtherInterface>(); 
ISomeOtherInterface someOtherObject = Container.GetObject<ISomeOtherInterface>(); 

ver? Solo un objeto para obtener varios objetos de tipo diferente y sin claves (las intefaces mismas son las claves). Si necesita un objeto para obtener varios objetos diferentes, pero todos implementan la misma interfaz, un IoC no lo ayudará mucho.

3

En las últimas semanas, he dado el salto de la inyección de dependencia solo a la inversión total de control con Castle, así que entiendo de dónde viene su pregunta.

Algunas de las razones por las que no se desea utilizar un recipiente COI:

  1. Es un proyecto pequeño que no va a crecer mucho. Si hay una relación 1: 1 entre los constructores y las llamadas a esos constructores, usar un contenedor IOC no reducirá la cantidad de código que tengo que escribir. No está violando "no se repita" hasta que se encuentre copiando y pegando exactamente el mismo "var myObject = new MyClass (someInjectedDependency)" por segunda vez.

  2. Es posible que tenga que adaptar el código existente para facilitar la carga en contenedores IOC. Probablemente esto no sea necesario hasta que entres en algunas de las características de programación orientadas a Aspect más geniales, pero si has olvidado hacer un método virtual, sella la clase de ese método, y no implementa una interfaz, y tú ' Es incómodo hacer esos cambios debido a las dependencias existentes, y luego hacer el cambio no es tan atractivo.

  3. Añade una dependencia externa adicional a mi proyecto, y a mi equipo. Puedo convencer al resto de mi equipo de que estructurar su código para permitir que DI se expanda, pero actualmente soy el único que sabe cómo trabajar con Castle. En proyectos más pequeños y menos complicados, esto no será un problema. Para los proyectos más grandes (que, irónicamente, obtendrían el mayor beneficio de los contenedores de IOC), si no puedo evangelizar usando un contenedor de IOC lo suficiente, ir mal de mi equipo no va a ayudar a nadie.

Algunas de las razones por las que no me gustaría volver a DI claro:

  1. puedo añadir o quitar el registro en cualquier número de mis clases, sin añadir ningún tipo de instrucción de rastreo o registro. Tener la capacidad de que mis clases se entrelacen con la funcionalidad adicional sin cambiar esas clases, es extremadamente poderosa. Por ejemplo:

    registro: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Transacciones: http://www.codeproject.com/KB/architecture/introducingcastle.aspx (pase directamente a la sección de Transacción)

  2. Castillo, al menos, es tan útil al cablear clases de dependencias, que sería doloroso para volver.

Por ejemplo, la falta de una dependencia con el castillo:

"No se puede crear el componente 'MiClase' como que tiene dependencias a ser satisfechos servicio es la espera de las siguientes dependencias .:

Servicios: - IMyService que no se ha registrado."

Missing una dependencia sin Castle:

referencia a objeto no se establece en un instancia de un objeto

Dead Última: La capacidad de intercambiar servicios inyectados en tiempo de ejecución, por editando un archivo Xml. Mi percepción es que esta es la característica más tautada, pero lo veo como una mera guinda del pastel. Prefiero cablear todos mis servicios en código, pero estoy seguro de que me encontraré con un dolor de cabeza en el futuro donde mi mente cambiará en esto.

Debo admitir que, siendo un novato en el COI y en el Castillo, probablemente solo esté rascando la superficie, pero hasta ahora, realmente me gusta lo que veo. Siento que los últimos proyectos que construí con ellos son realmente capaces de reaccionar a los cambios impredecibles que surgen día a día en mi compañía, una sensación que nunca antes había sentido.

1

Jeremy Frey echa de menos una de las principales razones para usar un contenedor de IOC: hace que su código sea más fácil de simular y probar.

Fomentar el uso de interfaces tiene muchos otros beneficios agradables: mejor estratificación, más fácil de generar dinámicamente proxies para cosas como transacciones declarativas, programación orientada a aspectos y remota.

Si crees que el COI solo sirve para reemplazar las llamadas a "nuevas", no lo obtienes.

+0

A propósito no mencioné las pruebas, porque él mencionó que ya está usando DI. Eso es todo lo que necesitas para burlarte y probar. DI es una estrategia; Los contenedores de IoC facilitan esa estrategia y la hacen más fácil de implementar (una reducción en su "código de macarrones") –

+1

Esto probablemente debería haber sido hecho como un comentario en la publicación de Jeremy ... –

13

Inversion of Control se trata principalmente de la gestión de la dependencia y proporciona código comprobable. Desde un enfoque clásico, si una clase tiene una dependencia, la tendencia natural es dar a la clase que tiene la dependencia control directo sobre la gestión de sus dependencias. Esto generalmente significa que la clase que tiene la dependencia 'actualizará' sus dependencias dentro de un constructor o bajo demanda en sus métodos.

Inversion of Control es solo eso ... invierte lo que crea dependencias, externaliza ese proceso y lo inyecta en la clase que tiene la dependencia. Usualmente, la entidad que crea las dependencias es lo que llamamos un contenedor IoC, que es responsable no solo de crear e inyectar dependencias, sino también de administrar sus vidas, determinar su estilo de vida (más sobre esto en un segundo) y también ofrece una variedad de otras capacidades. (Esto se basa en Castle MicroKernel/Windsor, que es mi contenedor de IoC de elección ... está sólidamente escrito, es muy funcional y extensible. Existen otros contenedores de IoC que son más simples si tiene necesidades más simples, como Ninject, Microsoft Unity y Spring.NET.)

Considere que tiene una aplicación interna que se puede usar en un contexto local o en un contexto remoto. Dependiendo de algunos factores detectables, su aplicación puede necesitar cargar implementaciones "locales" de sus servicios, y en otros casos puede necesitar cargar implementaciones "remotas" de sus servicios. Si sigue el enfoque clásico y crea sus dependencias directamente dentro de la clase que tiene esas dependencias, entonces esa clase se verá obligada a romper dos reglas muy importantes sobre el desarrollo de software: Separación de preocupaciones y Responsabilidad individual. Cruza los límites de la preocupación porque su clase ahora está preocupada tanto por su propósito intrínseco, como por la preocupación de determinar qué dependencias debe crear y cómo. La clase ahora también es responsable de muchas cosas, en lugar de una sola, y tiene muchas razones para cambiar: sus cambios de propósito intrínsecos, el proceso de creación para sus cambios de dependencias, la forma en que encuentra cambios de dependencias remotas, qué dependencias pueden necesitar sus dependencias , etc.

Al invertir su gestión de dependencias, puede mejorar la arquitectura de su sistema y mantener SoC y SR (o, posiblemente, lograrlo cuando no pudo debido a dependencias). Como una entidad externa, el contenedor IoC ahora controla cómo se crean e inyectan sus dependencias, también puede obtener capacidades adicionales. El contenedor puede administrar los ciclos de vida de sus dependencias, crearlas y destruirlas de maneras más flexibles que pueden mejorar la eficiencia. También obtienes la capacidad de administrar los estilos de vida de tus objetos. Si tiene un tipo de dependencia que se crea, utiliza y devuelve con mucha frecuencia, pero que tiene poco o ningún estado (por ejemplo, fábricas), puede darles un estilo de vida compartido, que le indicará al contenedor que cree automáticamente un grupo de objetos para ese tipo de dependencia particular. Existen muchos estilos de vida, y un contenedor como Castle Windsor generalmente te dará la posibilidad de crear el tuyo propio.

Los mejores contenedores IoC, como Castle Windsor, también proporcionan una gran capacidad de extensión. Por defecto, Windsor le permite crear instancias de tipos locales. Es posible crear instalaciones que amplíen las capacidades de creación tipo Windsor para crear dinámicamente proxies de servicio web y servidores de servicio WCF sobre la marcha, en tiempo de ejecución, eliminando la necesidad de crearlos manualmente o estáticamente con herramientas como svcutil (esto es algo que hice yo mismo recientemente .) Existen muchas instalaciones para que IoC admita marcos existentes, como NHibernate, ActiveRecord, etc.

Finalmente, IoC impone un estilo de codificación que garantiza el código de la unidad comprobable. Uno de los factores clave para hacer que la unidad de código sea comprobable es la gestión de la dependencia de externalización. Sin la capacidad de proporcionar dependencias alternativas (simulada, tropezada, etc.), probar una sola "unidad" de código de forma aislada es una tarea muy difícil, por lo que las pruebas de integración son el único estilo alternativo de prueba automatizada. Como IoC requiere que sus clases acepten dependencias mediante inyección (por constructor, propiedad o método), cada clase se reduce, si no siempre, a una sola responsabilidad de preocupación separada adecuadamente, y a dependencias totalmente burlables.

IoC = mejor arquitectura, mayor cohesión, separación mejorada de preocupaciones, clases que son más fáciles de reducir a una sola responsabilidad, dependencias fácilmente configurables e intercambiables (a menudo sin requerir una recompilación de su código), estilos de vida de dependencia flexibles y vida gestión del tiempo y código de prueba de la unidad. IoC es una especie de estilo de vida ... una filosofía, un enfoque para resolver problemas comunes y conocer las mejores prácticas críticas como SoC y SR.

Incluso (o mejor dicho, particularmente) con cientos de implementaciones diferentes de una sola interfaz, IoC tiene mucho que ofrecer. Puede tomar un tiempo para que su cabeza quede totalmente envuelta, pero una vez que comprenda completamente qué es IoC y qué puede hacer por usted, nunca querrá hacer las cosas de otra manera (excepto tal vez el desarrollo de sistemas integrados ...)

+2

Muy buena respuesta. – Klinger

+0

¡Gracias por esta explicación! – John

0

Los contenedores IoC generalmente realizan las inyecciones de dependencia que en algunos proyectos no son un gran problema, pero algunos de los marcos que proporcionan contenedores IoC ofrecen otros servicios que hacen que valga la pena usarlos. Castle, por ejemplo, tiene una lista completa de servicios además de un contenedor IoC.Dynamic proxies, gestión de transacciones y las instalaciones de NHibernate son algunos de ellos. Entonces, creo que debería considerar a los contianers de IoC como parte de un marco de aplicación.

He aquí por qué utilizo un contenedor IoC: pruebas unitarias 1.Writing serán más fáciles de escribir .Actually diferentes configuraciones para hacer diferentes cosas 2.Adding diferentes plugins para diferentes escenarios (para diferentes clientes, por ejemplo) 3. Interceptar clases para agregar diferentes aspectos a nuestro código. 4. Debido a que estamos usando NHibernate, la administración de transacciones y las instalaciones de NHibernate de Castle son muy útiles para desarrollar y mantener nuestro código. Es como que todos los aspectos técnicos de nuestra aplicación se manejan usando un marco de aplicación y tenemos tiempo para pensar qué es lo que los clientes realmente desean.

Cuestiones relacionadas