¿Se deben realizar dependencias de inyección en el ctor o por método?

14

Considera:

public class CtorInjectionExample
{
    public CtorInjectionExample(ISomeRepository SomeRepositoryIn, IOtherRepository OtherRepositoryIn)
    {
        this._someRepository = SomeRepositoryIn;
        this._otherRepository = OtherRepositoryIn;
    }

    public void SomeMethod()
    {
        //use this._someRepository
    }

    public void OtherMethod()
    {
        //use this._otherRepository
    }
}

en contra:

public class MethodInjectionExample
{
    public MethodInjectionExample()
    {
    }

    public void SomeMethod(ISomeRepository SomeRepositoryIn)
    {
        //use SomeRepositoryIn
    }

    public void OtherMethod(IOtherRepository OtherRepositoryIn)
    {
        //use OtherRepositoryIn
    }
}

Aunque la inyección de Ctor dificulta la extensión (cualquier código que llame al ctor deberá actualizarse cuando se agreguen nuevas dependencias), y la inyección a nivel de método parece permanecer más encapsulada desde la dependencia de nivel de clase y no puedo encontrar ningún otro argumento para / en contra de estos enfoques.

¿Hay un enfoque definitivo para inyectarse?

(N.B. He buscado información sobre esto y he intentado que esta pregunta sea objetiva.)

    
pregunta StuperUser 03.04.2012 - 15:06

4 respuestas

3

Depende, si el objeto inyectado es utilizado por más de un método en la clase, e inyectarlo en cada método no tiene sentido, debe resolver las dependencias para cada llamada de método, y si la dependencia es utilizado solo por un método inyectar en el constructor no es bueno, pero como está asignando recursos que nunca podrían usarse.

    
respondido por el nohros 03.04.2012 - 16:51
12

Bien, primero que nada, tratemos con "Cualquier código que llame al ctor deberá actualizarse cuando se agreguen nuevas dependencias"; Para ser claros, si está realizando una inyección de dependencia y tiene algún código que llama a new () en un objeto con dependencias, lo está haciendo mal .

Su contenedor DI debe poder inyectar todas las dependencias relevantes, por lo que no tiene que preocuparse por cambiar la firma del constructor, por lo que el argumento realmente no se sostiene.

En cuanto a la idea de inyección por método versus por clase, hay dos problemas principales con la inyección por método.

Un problema es que los métodos de su clase deben compartir dependencias, es una forma de ayudar a asegurarse de que sus clases estén separadas de manera efectiva, si ve una clase con un gran número de dependencias (probablemente más de 4-5), entonces esa clase es un candidato principal para refactorizar en dos clases.

El siguiente problema es que para "inyectar" las dependencias, por método, tendrías que pasarlas a la llamada de método. Esto significa que tendrá que resolver las dependencias antes de la llamada al método, por lo que probablemente terminará con un montón de código como este:

var someDependency = ServiceLocator.Resolve<ISomeDependency>();
var something = classBeingInjected.DoStuff(someDependency);

Ahora, diga que va a llamar a este método en 10 lugares alrededor de su aplicación: tendrá 10 de estos fragmentos. Luego, diga que necesita agregar otra dependencia a DoStuff (): tendrá que cambiar ese fragmento 10 veces (o envolverlo en un método, en cuyo caso simplemente está replicando el comportamiento de DI manualmente, lo que es un desperdicio). de tiempo).

Entonces, lo que básicamente has hecho es hacer que tus clases que utilizan DI sean conscientes de su propio contenedor DI, que es una idea fundamentalmente mala , ya que conduce muy rápidamente a un diseño torpe que es Difícil de mantener.

Compare eso con la inyección del constructor; En la inyección de constructores no está atado a un contenedor DI particular, y nunca es directamente responsable de cumplir con las dependencias de sus clases, por lo que el mantenimiento es bastante sencillo.

Me parece que estás tratando de aplicar IoC a una clase que contiene un montón de métodos de ayuda no relacionados, mientras que es mejor dividir la clase de ayuda en una serie de clases de servicio según el uso, y luego usar la ayuda para delegar las llamadas. Este todavía no es un gran enfoque (el ayudante clasificado con métodos que hacen algo más complejo que solo tratar con los argumentos que se les pasan son generalmente clases de servicio mal escritas), pero al menos mantendrá su diseño un poco más limpio .

(NB: He hecho el enfoque que está sugiriendo antes y fue una muy mala idea que no haya repetido desde entonces. Resultó que estaba tratando de separar las clases que realmente no necesitaban ser separadas, y terminó con un conjunto de interfaces donde cada llamada de método requería una selección casi fija de otras interfaces. Era una pesadilla mantener.)

    
respondido por el Ed James 03.04.2012 - 15:26
3

Hay varios tipos de inversión de control , y su pregunta propone solo dos (también puede usar la fábrica para inyectar dependencia).

La respuesta es: depende de la necesidad. A veces es mejor usar un tipo y otro tipo diferente.

Personalmente, me gustan los inyectores de constructores, ya que el constructor está allí para inicializar completamente el objeto. Tener que llamar a un setter más adelante hace que el objeto no esté completamente construido.

    
respondido por el BЈовић 03.04.2012 - 15:19
3

Te perdiste el que al menos para mí es la inyección de propiedades más flexible. Utilizo Castle / Windsor y todo lo que necesito hacer es agregar una nueva propiedad automática a mi clase y obtengo el objeto inyectado sin ningún problema y sin interrumpir ninguna interfaz.

    
respondido por el Otávio Décio 03.04.2012 - 15:26