Considerar:
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
}
}
Si bien la inyección de Ctor dificulta la extensión (cualquier código que llame al ctor necesitará actualizarse cuando se agreguen nuevas dependencias), y la inyección a nivel de método parece permanecer más encapsulada de la dependencia a nivel de clase y no puedo encontrar ningún otro argumento a favor / en contra de estos enfoques .
¿Existe un enfoque definitivo para tomar para inyección?
(Nota: he buscado información sobre esto y he tratado de hacer que esta pregunta sea objetiva).
Respuestas:
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 al método, y si la dependencia es utilizada solo por un método inyectado en el constructor no es bueno, pero dado que está asignando recursos que nunca podrían usarse.
fuente
Bien, en primer lugar, tratemos con "Cualquier código que llame al ctor deberá actualizarse cuando se agreguen nuevas dependencias"; Para ser claros, si está haciendo 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 debería ser capaz de inyectar todas las dependencias relevantes, por lo que no debe preocuparse por cambiar la firma del constructor, de modo que ese argumento realmente no sea válido.
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 una gran cantidad 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ía que pasarlas a la llamada al 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:
Ahora, supongamos que va a llamar a este método en 10 lugares alrededor de su aplicación: tendrá 10 de estos fragmentos. Luego, digamos que necesita agregar otra dependencia a DoStuff (): tendrá que cambiar ese fragmento 10 veces (o envolverlo en un método, en cuyo caso solo está replicando el comportamiento de DI manualmente, lo cual es un desperdicio de tiempo).
Entonces, lo que básicamente ha hecho allí es hacer que sus clases que utilizan DI sean conscientes de su propio contenedor de DI, lo cual es una idea fundamentalmente mala , ya que rápidamente conduce a un diseño torpe que es difícil de mantener.
Compare eso con la inyección del constructor; En la inyección de constructor, 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 libre de dolor de cabeza.
Me parece que está tratando de aplicar IoC a una clase que contiene un montón de métodos auxiliares no relacionados, mientras que es mejor dividir la clase auxiliar en una serie de clases de servicio en función del uso, luego usar el auxiliar para delegar el llamadas. Esto todavía no es un gran enfoque (ayudante clasificado con métodos que hacen algo más complejo que solo lidiar con los argumentos que se les pasan, generalmente son solo clases de servicio mal escritas), pero al menos mantendrá su diseño un poco más limpio .
(Nota: he hecho el enfoque que estás 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 separarse, y terminé con un conjunto de interfaces donde cada llamada al método requería una selección casi fija de otras interfaces. Fue una pesadilla mantener).
fuente
"if you're doing dependency injection and you have any code calling new() on an object with dependencies, you're doing it wrong."
Si está probando un método en una clase, debe crear una instancia o ¿usa DI para crear una instancia de su Código bajo prueba?"any code calling the ctor will need updating"
mi código de producción no llama a los ctors. Por estas razones.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 diferente.
Personalmente, me gustan los inyectores de constructor, 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.
fuente
Te perdiste el que al menos para mí es el más flexible: la inyección de propiedades. Uso 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 romper ninguna interfaz.
fuente