2012-01-26 12 views
6

Bien, hace poco que he estado leyendo en ninject pero estoy teniendo problemas para entender qué es lo que lo hace mejor sobre por qué se refieren a como 'pobre' DI en la página wiki. Lo triste es que fui sobre todas sus páginas en la wiki y todavía no lo entiendo = (¿Tiene problemas para entender ninject (o solo el contenedor IOC en general) con respecto a la DI de fábrica?

Normalmente voy a envolver mis clases de servicio en un patrón de fábrica que se encarga de la DI, así:.

public static class SomeTypeServiceFactory 
{ 
    public static SomeTypeService GetService() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 
     return = new SomeTypeService(someTypeRepository); 

    } 

} 

que me parece mucho a los módulos:

public class WarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<IWeapon>().To<Sword>(); 
     Bind<Samurai>().ToSelf().InSingletonScope(); 
    } 
} 

Donde cada clase tendría que está módulo asociado y enlazarlo del constructor para una aplicación concreta Mientras que el código ninject es 1 línea menos yo no estoy viendo. la ventaja, siempre que agregue/elimine constructores o cambie el implementación de un constructor de interfaz, tendría que cambiar el módulo más o menos de la misma manera que lo haría en la fábrica no? Entonces no veo la ventaja aquí.

Entonces pensé que podía llegar a una fábrica genérica convención basada modo:

public static TServiceClass GetService<TServiceClass>() 
     where TServiceClass : class 
    { 
     TServiceClass serviceClass = null; 

     string repositoryName = typeof(TServiceClass).ToString().Replace("Service", "Repository"); 
     Type repositoryType = Type.GetType(repositoryName); 

     if (repositoryType != null) 
     { 
      object repository = Activator.CreateInstance(repositoryType); 
      serviceClass = (TServiceClass)Activator.CreateInstance(typeof (TServiceClass), new[]{repository}); 
     } 

     return serviceClass; 
    } 

Sin embargo, esto es horrible por 2 razones: 1) Su depende fuertemente de la convención de nomenclatura, 2) Asumió el repositorio nunca tendrá constructores (no es verdadero) y el único constructor del servicio será su correspondiente repositorio (tampoco es cierto). Me dijeron "hey aquí es donde deberías usar un contenedor IoC, ¡sería genial aquí!" Y así comenzó mi investigación ... pero simplemente no lo veo y estoy teniendo problemas para entenderlo ...

¿Hay alguna manera en que ninject pueda resolver automáticamente los constructores de una clase sin una declaración específica tal que sería genial para usar en mi fábrica genérica (también me doy cuenta de que podría hacer esto manualmente utilizando la reflexión, pero eso es un golpe de rendimiento y ninject dice que en su página no usan el reflejo).

¡Sería muy útil aclarar este problema y/o mostrar cómo se podría usar en mi fábrica de genéricos!

EDIT: Respuesta

así que gracias a la explicación de abajo estaba hábilmente para entender completamente la maravilla de ninject y mi fábrica genérica se ve así:

public static class EntityServiceFactory 
{ 
    public static TServiceClass GetService<TServiceClass>() 
     where TServiceClass : class 
    { 
     IKernel kernel = new StandardKernel(); 

     return kernel.Get<TServiceClass>(); 
    } 
} 

bastante impresionante. Todo se maneja automáticamente ya que las clases concretas tienen un enlace implícito.

+0

Comentario de registro de bits habitual: ejecute [Inyección de dependencia en .NET libro mi Mark Seemann] (http.commanning.com/seemann). No puedo imaginar que no te sientas seguro del por qué y cómo de DI (el patrón) y los contenedores DI en una semana después de ser el propietario del libro. –

Respuesta

7

El beneficio de los contenedores de IoC crece con el tamaño del proyecto. Para proyectos pequeños, su beneficio en comparación con "DI del pobre" como su fábrica es mínimo. Imagine un gran proyecto que tiene miles de clases y algunos servicios se utilizan en muchas clases. En este caso, solo tiene que decir una vez cómo se resuelven estos servicios. En una fábrica, tienes que hacerlo una y otra vez para cada clase.

Ejemplo: Si tiene un servicio MyService : IMyService y una clase A que requiere IMyService, debe decirle a Ninject cómo resolverá estos tipos, como en su fábrica. Aquí el beneficio es mínimo. Pero tan pronto como el proyecto crezca y agregue una clase B que también depende de IMyService, solo tiene que decirle a Ninject cómo resolver B. Ninject ya sabe cómo obtener el IMyService. En la fábrica, por otro lado, debe definir de nuevo cómo B obtiene su IMyService.

Para ir un paso más allá. No debería definir enlaces uno por uno en la mayoría de los casos. En su lugar, use la configuración basada en convenciones (Ninject.Extension.Conventions). Con esto puedes agrupar clases juntas (Servicios, Repositorios, Controladores, Presentadores, Vistas, ....) y configurarlas de la misma manera. P.ej. decirle a Ninject que todas las clases que finalicen con el Servicio serán simples y publicarán todas sus interfaces. De esta forma, tiene una sola configuración y no se requieren cambios cuando agrega otro servicio.

También los contenedores IoC no son solo fábricas. Hay mucho más P.ej. Gestión del ciclo de vida, intercepción, ...

kernel.Bind(
    x => x.FromThisAssembly() 
      .SelectAllClasses() 
      .InNamespace("Services") 
      .BindToAllInterfaces() 
      .Configure(b => b.InSingletonScope())); 
kernel.Bind(
    x => x.FromThisAssembly() 
      .SelectAllClasses() 
      .InNamespace("Repositories") 
      .BindToAllInterfaces()); 
+0

Veo (la misma pregunta que con la otra respuesta), ¿entonces realmente ninject no me va a ayudar a hacer una implementación genérica de una fábrica? ¿O de alguna manera resolver automáticamente las dependencias sin que yo las declare? En cuanto a usarlo para no tener un módulo/fábrica para cada clase de servicio individual. Además, ¿qué pasa si mis repositorios y servicios tienen cantidades variables de inyecciones, las convenciones no podrían realmente ser utilizadas, entonces podría? – SventoryMang

+1

Parece que no entiendes cómo funciona ninject. Mira al constructor y luego trata de obtener las dependencias correctas de la configuración. Por lo tanto, las clases con los diferentes números de dependencias se pueden configurar fácilmente utilizando la misma convención. –

+0

Hmm I * think * Entiendo ahora. Por lo tanto, no puede ayudarme con mi fábrica de genéricos, ¿correcto? Todavía tengo que configurar las inyecciones de manera declarativa en algún momento, lo que significa que realmente no puedo hacer un genérico aquí. ¿Tiene un ejemplo de uso de convenciones con números variables de dependencias? Lo siento por ser tan grueso aquí = (. Estoy teniendo un momento difícil para extrapolar lo que está en el sitio a mi propio escenario. – SventoryMang

2

Para ser análogo completamente su código de fábrica debe decir:

public static class SomeTypeServiceFactory 
{ 
    public static ISomeTypeService GetService() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 

     // Somewhere in here I need to figure out if i'm in testing mode 
     // and i have to do this in a scope which is not in the setup of my 
      // unit tests 

     return new SomeTypeService(someTypeRepository); 
    } 

    private static ISomeTypeService GetServiceForTesting() 
    { 
     SomeTypeRepository someTypeRepository = new SomeTypeRepository(); 
     return new SomeTestingTypeService(someTypeRepository); 
    } 
} 

Y el equilvalent en Ninject sería:

public class WarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<ISomeTypeService>().To<SomeTypeService>(); 
    } 
} 

public class TestingWarriorModule : NinjectModule { 
    public override void Load() { 
     Bind<ISomeTypeService>().To<SomeTestingTypeService>(); 
    } 
} 

Aquí, se pueden definir las dependencias de forma declarativa, asegurando que las únicas diferencias entre su prueba y el código de producción están contenidos en la fase de configuración.

La ventaja de un IoC no es que no tiene que cambiar el módulo cada vez que cambia la interfaz o el constructor, es el hecho de que puede declarar las dependencias declarativamente y que puede enchufar y reproducir diferentes módulos para diferentes propósitos.

+0

Ya veo, ¿entonces realmente ninject no me va a ayudar a hacer una implementación genérica de una fábrica? ¿O de alguna manera resolver automáticamente las dependencias sin que yo las declare? En cuanto a usarlo para no tener un módulo/fábrica para cada clase de servicio individual. – SventoryMang

Cuestiones relacionadas