15

He estado aprendiendo IoC, Dependency Injection etc. y disfrutando el proceso. Los beneficios de desacoplar y programar interfaces son, para mí, una obviedad.Cómo desacoplar la implementación del Framework IoC

Sin embargo, realmente no me gusta vincularme a un marco específico como Unity, Autofac o Windsor, porque todavía estoy aprendiendo y todavía no he decidido cuál es el mejor para mis propósitos.

Entonces, ¿cómo puedo envolver algo como Unity para poder cambiar fácilmente en Windsor en una fecha posterior? (o lo que sea). Y no se atreva a decir que use otro para inyectar el primero;)

¡Gracias!

R.

P.s. Llamé a Unity porque esa es mi preferencia personal actual (me acabo de enterar de Entlib).

Respuesta

18

Sin duda puede tratar de hacer una abstracción del contenedor al declarar IContainer con decir Resolve y Register. Lo hice un par de veces. Luego, seguiría adelante e implementaría un contenedor : IContainer y encapsularía un contenedor de IoC real con su abstracción. Lo intenté con Unity y Castle Windsor.

Pero bueno, pronto me di cuenta de que esto era realmente una sobreingeniería. Luego entendí que traté de abstraerme de la abstracción, pero construir otra abstracción. Esto podría estar bien para aprender el concepto, pero fue un verdadero dolor en el cuello en un proyecto real. Recomiendo encarecidamente contra una abstracción del contenedor IoC. Si usa correctamente el principio de DI, será bastante fácil cambiar su contenedor de todos modos.

El código es excesivamente complicada, como

//I did this mess with Service Locator 
var t = ContainerService.Instance.Resolve<IMyType>(); 
//others could go further with same Service Locator 
var t = IoCFactory.Instance.CurrentContainer.Resolve<IMyType>(); 

//better way, use --> IoC and DI <-- 
//when a program starts, or a new instance of the context created 
var t = Container.Resolve<IMyType>() //this lives at the bottom of the stack 
//and then you just pass IMyType to the constructor of other types  
//you don't need to call Resolve again in the logical cycle 

Ver this post por Ayende.

Sí, resumieron la inversión del contenedor de control. Creo que si necesitas hacer eso, está bastante claro que realmente no obtienes lo que es el IoC.

+0

buen punto, resúmenes IoC suena como overdesign – pkmiec

+0

Tiene toda la razón, esto es por requisitos de aprendizaje. Una vez que me instale en mi contenedor de jour, estaría feliz. Pero cuando estás aprendiendo y teniendo que reescribir aplicaciones para atender otro contenedor porque el ejemplo en un blog usa x en lugar de y, te llega luego de un tiempo. Pensé que sería bueno tener mi propio ejemplo y solo encontrar una manera de cambiar fácilmente cualquier contenedor que un blog estuviera usando para ilustrar un concepto en particular. – Richard

+0

Estoy de acuerdo, esto es excesivo. Un contenedor de IoC decente debería tener suficiente espacio para la configuración, de modo que no tenga que contaminar su código con referencias al contenedor. Si abstraer el contenedor es la única forma de hacerlo funcionar, entonces diría que está utilizando un contenedor de IoC deficiente. – FMM

3

Echa un vistazo a la biblioteca Common Service Locator.

+6

imho, CSL solo es realmente útil cuando se crea un componente que se utilizará en varios proyectos dispares que pueden elegir utilizar diferentes bibliotecas de IoC. Usar CSL uno mismo en su aplicación única de línea de negocio, por ejemplo, es excesivo. Agrega mucho en la administración de dependencias y proporciona solo una interfaz muy estrecha que podría ser simplemente específica en una biblioteca de infraestructura central de la aplicación. –

+3

Como uno de los diseñadores de CSL, apruebo firmemente el comentario anterior. CSL está destinado a los autores de bibliotecas que desean un contenedor, pero no desean forzar la selección de contenedor de la biblioteca en la aplicación. –

18

Use la inyección de constructor para comunicar qué dependencias necesita una clase. Todos los contenedores que figuran en la lista lo admiten.

A veces, una parte del código no puede lograr la independencia completa del contenedor, pero estos casos deben ser una parte muy pequeña de su base de código.

+5

Absolutamente adecuado para preferir la inyección de constructor. – FMM

4

Como algunas otras personas han mencionado, prefieren la inyección de constructor. Esto resolverá muchos de tus problemas.

Si sus clases tienen dependencias directas en el propio contenedor de IoC, tiende a ser una variante del uso del patrón de localización de servicios (anti-). En este caso particular, aísle qué tipos se están resolviendo mediante el localizador de servicios y resuma esa resolución dinámica con una interfaz de fábrica.Así, por ejemplo, sustituir este:

public class Foo 
{ 
    private MyIoCContainer _container; 

    public Foo(MyIoCContainer container) 
    { 
     this._container = container; 
    } 


    public void DoSomething() 
    { 
     // have to do this at runtime for whatever reason 
     var myObj = this._container.Resolve<ISomeType>(); 

     myObj.DoSomething(); 
     myObj.DoSomethingElse(); 
    } 
} 

con esto:

public class Foo 
{ 
    private IObjFactory _provider; 

    public Foo(IObjFactory _provider) 
    { 
     this._provider = provider; 
    } 


    public void DoSomething() 
    { 
     var myObj = _provider.GetObj(); 

     myObj.DoSomething(); 
     myObj.DoSomethingElse(); 
    } 
} 

public interface IObjFactory 
{ 
    ISomeType GetObj(); 
} 

Ahora, usted tiene una IObjFactory que puede encapsular la naturaleza dinámica, el tiempo de ejecución de la construcción de los objetos que implementan ISomeType. Si está construyendo muchos tipos diferentes de objetos desde el contenedor/localizador de servicios, entonces debe tener al menos la misma cantidad de interfaces *Factory (de acuerdo con Interface Segregation Principle).

9

A DI Container solo debe hacer referencia desde Composition Root. Todos los demás módulos no deberían tener ninguna referencia al contenedor.

-Mark Seemann (autor de Dependency Injection in .NET)

En otras palabras, sólo se debería necesitar cambiar una clase si cambia contenedores DI.

La inyección del constructor es normalmente el camino correcto, como han mencionado otros. Puede inyectar interfaces de fábrica o delegados Func<T> si necesita crear objetos sobre la marcha.

También sugiero evitar la configuración XML siempre que sea posible.

Cuestiones relacionadas