He visto varios recomendar el uso de contenedores IoC en el código. La motivación es simple. Tome el siguiente código inyectado de dependencia:
class UnitUnderTest
{
std::auto_ptr<Dependency> d_;
public:
UnitUnderTest(
std::auto_ptr<Dependency> d = std::auto_ptr<Dependency>(new ConcreteDependency)
) : d_(d)
{
}
};
TEST(UnitUnderTest, Example)
{
std::auto_ptr<Dependency> dep(new MockDependency);
UnitUnderTest uut(dep);
//Test here
}
Dentro:
class UnitUnderTest
{
std::auto_ptr<Dependency> d_;
public:
UnitUnderTest()
{
d_.reset(static_cast<Dependency *>(IocContainer::Get("Dependency")));
}
};
TEST(UnitUnderTest, Example)
{
UnitUnderTest uut;
//Test here
}
//Config for IOC container normally
<Dependency>ConcreteDependency</Dependency>
//Config for IOC container for testing
<Dependency>MockDependency</Dependency>
(Lo anterior es un ejemplo hipotético de C ++, por supuesto)
Si bien estoy de acuerdo en que esto simplifica la interfaz de la clase al eliminar el parámetro del constructor de dependencias, creo que la cura es peor que la enfermedad por un par de razones. Primero, y esto es muy importante para mí, esto hace que su programa dependa de un archivo de configuración externo. Si necesita una implementación binaria única, simplemente no puede usar este tipo de contenedores. El segundo problema es que la API ahora es débil y peor, tipada en cadena . La evidencia (en este ejemplo hipotético) es el argumento de cadena del contenedor de IoC y el reparto del resultado.
Entonces, ¿hay otros beneficios de usar este tipo de contenedores o simplemente no estoy de acuerdo con los que recomiendan los contenedores?
fuente
Respuestas:
En una aplicación grande con muchas capas y muchas partes móviles, son los inconvenientes los que comienzan a parecer bastante menores en comparación con las ventajas.
El contenedor "simplifica la interfaz" de la clase, pero lo hace de una manera muy importante. El contenedor es una solución al problema que crea la inyección de dependencias, que es la necesidad de pasar dependencias por todo el lugar, a través de gráficos de objetos y áreas funcionales. Aquí tiene un pequeño ejemplo que tiene una dependencia: ¿qué pasa si este objeto tiene tres dependencias y los objetos que dependen de él tienen múltiples objetos que dependen de ellos , y así sucesivamente? Sin un contenedor, los objetos en la parte superior de esas cadenas de dependencia terminan siendo responsables de realizar un seguimiento de todas las dependencias en toda la aplicación.
También hay diferentes tipos de contenedores. No todos están escritos en cadena y no todos requieren archivos de configuración.
fuente
El marco Guice IoC de Java no se basa en un archivo de configuración sino en un código de configuración . Esto significa que la configuración es un código que no difiere del código que constituye su aplicación real, y se puede refactorizar, etc.
Creo que Guice es el marco de Java IoC que finalmente consiguió la configuración correcta.
fuente
Esta gran respuesta SO de Ben Scheirman detalla algunos ejemplos de código en C #; Algunas ventajas de los contenedores IoC (DI) son:
fuente