2011-04-06 20 views
7

Ésta es una extensión a la pregunta Why do I need an IoC container as opposed to straightforward DI code?aún necesita ayuda para entender por qué Ninject podría ser mejor que DI manual de

He estado aprendiendo Ninject y se acercó con el siguiente ejemplo, el ejemplo va a través de la forma manual haciendo DI y la manera Ninject de hacer DI:

class Program 
{ 
    static void Main(string[] args) 
    { 
     NinjectWay(); 
     ManualWay(); 
     Console.ReadKey(); 
    } 

    private static void ManualWay() 
    { 
     Console.WriteLine("ManualWay***********************"); 
     IWeapon sword = new Sword(); 
     Samurai samurai = new Samurai(sword); 

     Console.WriteLine(samurai.Attack("ManualWay...")); 

     // change weapon 
     IWeapon dagger = new Dagger(); 
     samurai.Weapon = dagger; 

     Console.WriteLine(samurai.Attack("ManualWay...")); 

     IWeapon weapon = new Shuriken(); 
     IWarrior ninja = new Ninja(weapon); 
     Console.WriteLine("Manual way.. inject shuriken when a ninja. " + ninja.Weapon.Name); 

     IWarrior ninja2 = new Ninja(weapon); 
    } 

    private static void NinjectWay() 
    { 
     Console.WriteLine("NinjectWay***********************"); 
     IKernel kernel = new StandardKernel(); 
     kernel.Bind<IWeapon>().To<Sword>(); 
     var samurai = kernel.Get<Samurai>(); 

     Console.WriteLine(samurai.Attack("NinjectWay...")); 

     kernel.Rebind<IWeapon>().To<Dagger>(); 
     samurai = kernel.Get<Samurai>(); 

     Console.WriteLine(samurai.Attack("NinjectWay...")); 

     kernel.Bind<IWeapon>().To<Shuriken>().WhenInjectedInto<Ninja>(); 
     var ninja = kernel.Get<Ninja>(); 
     ninja.OffHandWeapon = new ShortSword(); 

     Console.WriteLine("Conditional Injection..."+ninja.Weapon.Name); 
     Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja.OffHandWeapon.Name); 

     var ninja2 = kernel.Get<Ninja>(); 
     Console.WriteLine("Conditional Injection..." + ninja2.Weapon.Name); 
     Console.WriteLine("Conditional Injection: OffhandWeapon = " + ninja2.OffHandWeapon.Name); 

     Console.WriteLine(""); 
    } 
} 

Oigo los beneficios que suceden cuando la escala del proyecto aumenta pero no lo veo. Ayúdame a entender esto mejor. Proporcione más ejemplos en C#/Ninject y ayúdeme a entender dónde se hacen evidentes los beneficios.

Respuesta

5

A diferencia de las otras respuestas, sugieren que Ninject no se trata principalmente de hacer que su código sea más comprobable. ¡Es la Inyección de Dependencia lo que hace que tu código sea más comprobable! La Inyección de Dependencia se puede usar sin un contenedor IoC creando todo en facotries. Pero seguro, el poder reemplazar algunas partes fácilmente para Las pruebas de integración (no use pruebas de Ninject en unidades) es un buen efecto secundario.

Los contenedores IoC como Ninject son principalmente acerca de poner sus clases juntas en un software en funcionamiento. En proyectos pequeños esto puede hacerse fácilmente usando algunas fábricas. Pero a medida que su aplicación crece, las fábricas se vuelven cada vez más complicadas. Imagine una aplicación que tiene varios servicios; algunos de ellos se reutilizan, otros se crean para cada uso. Algunos de los servicios también son utilizados por varios componentes.

Si está utilizando un contenedor de IoC, debe definir exactamente una vez cómo obtiene la instancia de servicio y cuál es su ciclo de vida. Por otro lado, en una fábrica debe especificar cómo obtiene la instancia para cada clase que necesita una instancia (por ejemplo, nueva MyServiceFactory(). CreateInstance()). Además, debe controlar el ciclo de vida de forma manual.

Esto significa que a medida que crece el proyecto, la configuración de un contenedor IoC crece de forma lineal junto con el tamaño del proyecto. Pero una fábrica, por otro lado, crece más exponencialmente, ya que hay servicios que se utilizan en toda la aplicación (por ejemplo, autenticación de usuario).

BTW: Su ejemplo no es muy bueno porque Reencaminar no es una acción común. Por lo general, la configuración se realiza solo una vez al inicio de la aplicación.

0

Un beneficio viene en las pruebas.

Puede vincular Sword a IWeapon en su código de producción, y FakeSword a IWeapon en su ensamblaje de prueba. Esto es útil cuando necesitas probar algo que tiene una dependencia en IWeapon pero realmente no quieres una espada real.

Por ejemplo, en lugar de Sword y IWeapon tiene IDataContext y DataContext. Excelente en su código de producción cuando necesita conectarse a un DB. Sin embargo, para las pruebas unitarias, probablemente no desee llegar a la base de datos por varias razones (rendimiento, datos incoherentes, etc.). Por lo tanto, debe conectar un FakeDataContext a su IDataContext. Ahora tienes algo de control para simular la actividad de DB para probar.

0

¡GRAN PREGUNTA!

El BIG BIG win IMHO es cuando su código que pide instancias no sabe o no le importan cuáles son las implementaciones reales. Esto es más evidente en la burla: tu marco burlón puede configurar a Ninject para que devuelva los Ninja, Sword y Samarai burlados que implementen el comportamiento que esperas de formas completamente diferentes.

Tengo una capa de reposición, por ejemplo, que depende de IoC para obtener acceso a un data-store. Para las pruebas, ese data-store es una colección de objetos construida a mano. Para el acceso remoto, el data-store consume servicios web. Localmente, es SQL. El repositorio simplemente solicita IDataStore desde el IoC y obtiene todo lo configurado para servir.

¿Eso ayuda?

0

La principal ventaja que Ninject tiene sobre ti al hacerlo manualmente es que alguien más ha hecho muchos de los resúmenes por ti. Claramente, usted podría reproducir algo similar escribiendo un código similar a Ninject (algo para crear los objetos basados ​​en tipos de interfaz), lo que le permitiría separar la construcción de su objeto de la lógica de su objeto, pero Ninject (y otras bibliotecas) ya tienen listo un Mucho del trabajo duro para ti, a menos que vayas a agregar algo nuevo, ¿por qué querrías volver a crearlo?

La comparación que tienes en tu pregunta no es realmente representativa de la forma en que esperaría que se usara Ninject. Estás vinculando y reenlazando en el mismo método que está utilizando los objetos. Esperaría que la configuración del contenedor se realice en otro lugar. Esto le permite cambiar la construcción (para que, por ejemplo, sea más fácil de probar creando objetos falsos) sin alterar el código que realmente usa el objeto construido.

Cuestiones relacionadas