Pregunta

Entiendo los beneficios de la inyección de dependencia en sí. Tomemos la primavera, por ejemplo. También entiendo los beneficios de otras características de Spring, como AOP, ayudantes de diferentes tipos, etc. Me pregunto, ¿cuáles son los beneficios de la configuración XML como:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

comparado con el código java antiguo como:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

que es más fácil de depurar, se comprueba el tiempo de compilación y puede ser comprendido por cualquiera que sepa solo java. Entonces, ¿cuál es el propósito principal de un marco de inyección de dependencia? (o un fragmento de código que muestra sus beneficios).


ACTUALIZACIÓN:
En caso de

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

¿Cómo puede el marco de IoC adivinar qué implementación de myService quiero inyectar si hay más de una? Si solo hay una implementación de la interfaz dada, y dejo que el contenedor IoC decida automáticamente usarla, se romperá después de que aparezca una segunda implementación. Y si hay intencionalmente solo una posible implementación de una interfaz, entonces no necesita inyectarla.

Sería muy interesante ver una pequeña parte de la configuración de IoC que muestra sus beneficios. He estado usando Spring por un tiempo y no puedo dar ese ejemplo. Y puedo mostrar líneas individuales que demuestran los beneficios de hibernar, dwr y otros marcos que utilizo.


ACTUALIZACIÓN 2:
Me doy cuenta de que la configuración de IoC se puede cambiar sin recompilar. ¿Es realmente una buena idea? Puedo entender cuando alguien quiere cambiar las credenciales de la base de datos sin recompilar, puede que no sea desarrollador. En su práctica, ¿con qué frecuencia alguien que no sea desarrollador cambia la configuración de IoC? Creo que para los desarrolladores no hay ningún esfuerzo por recompilar esa clase en particular en lugar de cambiar la configuración. Y para aquellos que no sean desarrolladores, probablemente querrás facilitarle la vida y proporcionar un archivo de configuración más simple.


ACTUALIZACIÓN 3:

  

Configuración externa del mapeo entre interfaces y sus implementaciones concretas

¿Qué es tan bueno para hacerlo extenso? No hace que todo su código sea externo, mientras que definitivamente puede hacerlo, solo colóquelo en el archivo ClassName.java.txt, lea y compile manualmente sobre la marcha. Guau, evitó volver a compilar. ¿Por qué debería evitarse la compilación ?!

  

Se ahorra tiempo de codificación porque proporciona asignaciones de forma declarativa, no en un código de procedimiento

Entiendo que a veces el enfoque declarativo ahorra tiempo. Por ejemplo, solo declaro una vez que una asignación entre una propiedad de bean y una columna de base de datos e hibernación usa esta asignación al cargar, guardar, crear SQL basado en HSQL, etc. Aquí es donde funciona el enfoque declarativo. En el caso de Spring (en mi ejemplo), la declaración tenía más líneas y tenía la misma expresividad que el código correspondiente. Si hay un ejemplo en el que dicha declaración es más corta que el código, me gustaría verla.

  El principio de

Inversión de control permite realizar pruebas sencillas de unidades porque puede reemplazar implementaciones reales por falsas (como reemplazar una base de datos SQL por una en memoria)

Entiendo la inversión de los beneficios de control (prefiero llamar al patrón de diseño que se describe aquí como Inyección de dependencia, porque IoC es más general: hay muchos tipos de control y solo estamos invirtiendo uno de ellos: el control de inicialización) . Me preguntaba por qué alguien necesita algo más que un lenguaje de programación para eso. Definitivamente puedo reemplazar implementaciones reales con falsas usando código. Y este código expresará lo mismo que la configuración, simplemente inicializará los campos con valores falsos.

mary = new FakeFemale();

Entiendo los beneficios de DI. No entiendo qué beneficios agrega la configuración XML externa en comparación con el código de configuración que hace lo mismo. No creo que deba evitarse la compilación, compilo todos los días y sigo vivo. Creo que la configuración de DI es un mal ejemplo de enfoque declarativo. La declaración puede ser útil si se declara una vez Y se usa muchas veces de diferentes maneras, como hibernate cfg, donde la asignación entre la propiedad del bean y la columna de la base de datos se usa para guardar, cargar, crear consultas de búsqueda, etc. La configuración de Spring DI se puede traducir fácilmente a configurando código, como al principio de esta pregunta, ¿no es así? Y se usa solo para inicialización de frijol, ¿no es así? Lo que significa que un enfoque declarativo no agrega nada aquí, ¿verdad?

Cuando declaro el mapeo de hibernación, solo ofrezco hibernación de información, y funciona en base a ella, no le digo qué hacer. En el caso de la primavera, mi declaración le dice a la primavera exactamente qué hacer, entonces, ¿por qué declararla y por qué no hacerlo?


ÚLTIMA ACTUALIZACIÓN:
Chicos, muchas respuestas me están diciendo acerca de la inyección de dependencia, que sé que es bueno. La pregunta es sobre el propósito de la configuración de DI en lugar de inicializar el código. Tiendo a pensar que la inicialización del código es más breve y clara. La única respuesta que recibí hasta ahora a mi pregunta es que evita la recompilación cuando cambia la configuración. Supongo que debería publicar otra pregunta, porque es un gran secreto para mí, por qué debería evitarse la compilación en este caso.

¿Fue útil?

Solución

Para mí, una de las razones principales para usar una IoC (y hacer uso de la configuración externa) es alrededor de las dos áreas de:

  • Pruebas
  • Mantenimiento de producción

Pruebas

Si divide sus pruebas en 3 escenarios (lo cual es bastante normal en el desarrollo a gran escala):

  1. Pruebas unitarias
  2. Pruebas de integración
  3. Pruebas de caja negra

Lo que querrás hacer es que para los dos últimos escenarios de prueba (Integración y caja negra), no se vuelve a compilar ninguna parte de la aplicación.

Si alguno de sus escenarios de prueba requiere que cambie la configuración (es decir, use otro componente para imitar una integración bancaria o realice una carga de rendimiento), esto puede manejarse fácilmente (esto viene bajo los beneficios de configurar el DI lado de un IoC sin embargo.

Además, si su aplicación se usa en varios sitios (con una configuración de servidor y componente diferente) o tiene una configuración cambiante en el entorno real, puede usar las últimas etapas de las pruebas para verificar que la aplicación manejará esos cambios.

Producción

Como desarrollador, no tiene (y no debe) tener el control del entorno de producción (en particular cuando su aplicación se distribuye a varios clientes o sitios separados), para mí esto es el beneficio real de usar tanto un IoC y configuración externa, ya que depende del soporte de infraestructura / producción ajustar y ajustar el entorno en vivo sin tener que volver a los desarrolladores y realizar pruebas (un mayor costo cuando lo único que quieren es mover un componente).

Summary

Los principales beneficios de la configuración externa de un IoC provienen de otorgar a otros (no desarrolladores) el poder de configurar su aplicación, según mi experiencia, esto solo es útil en un conjunto limitado de circunstancias:

  • La aplicación se distribuye a múltiples sitios / clientes donde los entornos diferirán.
  • Control / entrada de desarrollo limitado en el entorno de producción y la configuración.
  • Escenarios de prueba.

En la práctica, he descubierto que incluso cuando desarrollas algo que sí tienes control sobre el entorno en el que se ejecutará, con el tiempo es mejor darle a alguien más la capacidad de cambiar la configuración:

  • Al desarrollar, no sabes cuándo cambiará (la aplicación es tan útil que tu empresa la vende a otra persona).
  • No quiero quedarme estancado con el cambio de código cada vez que se solicita un cambio leve que podría haberse manejado mediante la configuración y el uso de un buen modelo de configuración.

Nota: la aplicación hace referencia a la solución completa (no solo al ejecutable), por lo que todos los archivos necesarios para que la aplicación se ejecute .

Otros consejos

La inyección de dependencia es un estilo de codificación que tiene sus raíces en la observación de que la delegación de objetos suele ser un patrón de diseño más útil que la herencia de objetos (es decir, el objeto tiene: una relación es más útil que el objeto es una relación). Sin embargo, es necesario otro ingrediente para que funcione DI, el de crear interfaces de objeto. Combinando estos dos potentes patrones de diseño, los ingenieros de software se dieron cuenta rápidamente de que podían crear un código flexible y ligeramente acoplado, y así nació el concepto de inyección de dependencia. Sin embargo, no fue hasta que la reflexión de objetos estuvo disponible en ciertos lenguajes de alto nivel que DI realmente despegó. El componente de reflexión es el núcleo de la mayoría de los sistemas DI de hoy en día porque los aspectos realmente geniales de DI requieren la capacidad de seleccionar objetos y configurarlos e inyectarlos en otros objetos mediante un sistema externo e independiente a los propios objetos.

Un lenguaje debe proporcionar un buen soporte tanto para las técnicas de programación orientadas a objetos normales como para las interfaces de objetos y la reflexión de objetos (por ejemplo, Java y C #). Si bien puede crear programas utilizando patrones DI en sistemas C ++, su falta de soporte de reflexión dentro del lenguaje adecuado le impide admitir servidores de aplicaciones y otras plataformas DI y, por lo tanto, limita la expresividad de los patrones DI.

Fortalezas de un sistema construido usando patrones DI:

  1. El código DI es mucho más fácil de reutilizar, ya que la funcionalidad 'dependiente' se extrapola en interfaces bien definidas, lo que permite que los objetos separados cuya configuración es manejada por una plataforma de aplicación adecuada se puedan conectar a otros objetos a voluntad.
  2. El código DI es mucho más fácil de probar. La funcionalidad expresada por el objeto se puede probar en una caja negra construyendo objetos 'simulados' que implementan las interfaces esperadas por la lógica de su aplicación.
  3. El código DI es más flexible. Es un código acoplado de manera holgada, hasta un extremo. Esto permite al programador elegir y elegir cómo se conectan los objetos basándose exclusivamente en sus interfaces requeridas en un extremo y sus interfaces expresadas en el otro.
  4. La configuración externa (Xml) de objetos DI significa que otros pueden personalizar su código en direcciones imprevistas.
  5. La configuración externa también es un patrón de separación de preocupaciones en el sentido de que todos los problemas de la inicialización de objetos y la gestión de interdependencia de objetos pueden ser manejados por el servidor de aplicaciones.
  6. Tenga en cuenta que la configuración externa no es necesaria para usar el patrón DI, para interconexiones simples, un objeto pequeño constructor suele ser adecuado. Hay una compensación en la flexibilidad entre los dos. Un objeto generador no es una opción tan flexible como un archivo de configuración visible externamente. El desarrollador del sistema DI debe sopesar las ventajas de la flexibilidad sobre la conveniencia, cuidando que el control a pequeña escala y de grano fino sobre la construcción del objeto expresado en un archivo de configuración pueda aumentar la confusión y los costos de mantenimiento en el futuro.

Definitivamente el código DI parece más engorroso, las desventajas de tener todos esos archivos XML que configuran objetos para ser inyectados en otros objetos parecen difíciles. Este es, sin embargo, el punto de los sistemas DI. Su capacidad para mezclar y combinar objetos de código como una serie de ajustes de configuración le permite crear sistemas complejos utilizando códigos de terceros con una codificación mínima de su parte.

El ejemplo proporcionado en la pregunta simplemente toca la superficie del poder expresivo que puede proporcionar una biblioteca de objetos DI debidamente factorizada. Con algo de práctica y mucha autodisciplina, la mayoría de los profesionales de DI encuentran que pueden construir sistemas que tienen un 100% de cobertura de prueba del código de la aplicación. Este único punto es extraordinario. Esto no es una cobertura de prueba del 100% de una aplicación pequeña de unos pocos cientos de líneas de código, sino una cobertura de prueba del 100% de aplicaciones que comprenden cientos de miles de líneas de código. No puedo describir ningún otro patrón de diseño que proporcione este nivel de comprobabilidad.

Tiene razón en que una aplicación de apenas 10s de líneas de código es más fácil de entender que varios objetos más una serie de archivos de configuración XML. Sin embargo, al igual que con los patrones de diseño más potentes, los beneficios se encuentran a medida que continúa agregando nuevas funciones al sistema.

En resumen, las aplicaciones basadas en DI a gran escala son más fáciles de depurar y más fáciles de entender. Si bien la configuración Xml no está 'verificada el tiempo de compilación', todos los servicios de aplicación que este autor conoce le brindarán al desarrollador mensajes de error si intentan inyectar un objeto que tiene una interfaz incompatible en otro objeto. Y la mayoría proporciona una función de "verificación" que cubre todas las configuraciones de objetos conocidas. Esto se hace fácil y rápidamente al verificar que el objeto A a inyectar implementa la interfaz requerida por el objeto B para todas las inyecciones de objetos configurados.

Esta es una pregunta un poco cargada, pero tiendo a estar de acuerdo en que las enormes cantidades de configuración xml realmente no representan un gran beneficio. Me gusta que mis aplicaciones sean lo más ligeras posible con las dependencias, incluidos los marcos robustos.

Ellos simplifican el código muchas veces, pero también tienen una sobrecarga de complejidad que hace que sea muy difícil rastrear los problemas (he visto tales problemas de primera mano, y Java directo sería mucho más cómodo tratar con ellos) .

Supongo que depende del estilo un poco, y con lo que te sientas cómodo ... ¿te gusta volar tu propia solución y tienes la ventaja de saberlo al revés, o confiar en las soluciones existentes que pueden resultar difíciles cuando la configuración no es sólo la correcta? Es todo un compromiso.

Sin embargo, la configuración XML es un poco mi mascota ... Intento evitarla a toda costa.

Cada vez que puede cambiar su código a datos, está dando un paso en la dirección correcta.

Codificar cualquier cosa como datos significa que su propio código es más general y reutilizable. También significa que sus datos pueden especificarse en un idioma que se ajuste exactamente a ellos.

Además, un archivo XML se puede leer en una GUI o alguna otra herramienta y se puede manipular fácilmente de manera pragmática. ¿Cómo harías eso con el ejemplo de código?

Constantemente factorizo ??las cosas que la mayoría de la gente implementaría como código en datos, hace que el código quede MUCHO más limpio. Me parece inconcebible que la gente cree un menú en código en lugar de en datos, debería ser obvio que hacerlo en código es simplemente incorrecto debido a la repetición.

La razón para usar un contenedor DI es que no tiene que tener mil millones de propiedades preconfiguradas en su código que son simplemente captadoras y definidoras. ¿De verdad quieres codificar a todos aquellos con nueva X ()? Claro, puede tener un valor predeterminado, pero el contenedor DI permite la creación de singletons, que es extremadamente fácil y le permite centrarse en los detalles del código, no en la tarea diversa de inicializarlo.

Por ejemplo, Spring le permite implementar la interfaz InitializingBean y agregar un método afterPropertiesSet (también puede especificar un " init-method " para evitar el acoplamiento de su código con Spring). Estos métodos le permitirán asegurarse de que cualquier interfaz especificada como campo en su instancia de clase esté configurada correctamente al iniciarse, y luego ya no tendrá que verificar en forma nula a sus captadores y definidores (suponiendo que permita que sus singletons permanezcan seguros para la seguridad de subprocesos) ).

Además, es mucho más fácil hacer inicializaciones complejas con un contenedor DI en lugar de hacerlo usted mismo. Por ejemplo, ayudo con el uso de XFire (no CeltiXFire, solo usamos Java 1.4). La aplicación usó Spring, pero desafortunadamente usó el mecanismo de configuración services.xml de XFire. Cuando una colección de elementos necesitaba declarar que tenía CERO o más instancias en lugar de UNA o más instancias, tuve que anular parte del código XFire proporcionado para este servicio en particular.

Hay ciertos valores por defecto de XFire definidos en su esquema de beans de Spring. Entonces, si estuviéramos usando Spring para configurar los servicios, los beans podrían haber sido usados. En cambio, lo que sucedió fue que tuve que proporcionar una instancia de una clase específica en el archivo services.xml en lugar de usar los beans. Para hacer esto, necesitaba proporcionar el constructor y configurar las referencias declaradas en la configuración de XFire. El verdadero cambio que necesitaba hacer requería que sobrecargara una sola clase.

Pero, gracias al archivo services.xml, tuve que crear cuatro nuevas clases, configurando sus valores predeterminados de acuerdo con sus valores predeterminados en los archivos de configuración de Spring en sus constructores. Si hubiéramos podido utilizar la configuración de Spring, podría haberlo dicho:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

En cambio, se parecía más a esto:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

El resultado neto es que cuatro clases de Java adicionales, en su mayoría sin sentido, tuvieron que agregarse a la base de código para lograr el efecto que una clase adicional y cierta información de contenedor de dependencia simple lograron. Esta no es la " excepción que prueba la regla " ;, esta es la regla ... el manejo de las peculiaridades en el código es mucho más limpio cuando las propiedades ya están incluidas en un contenedor DI y simplemente las está cambiando para adaptarse a una situación especial , lo que sucede más a menudo que no.

Tengo tu respuesta

Obviamente, hay enfoques en cada enfoque, pero los archivos de configuración XML externalizados son útiles para el desarrollo empresarial en el que los sistemas de compilación se utilizan para compilar el código y no su IDE. Usando el sistema de compilación, es posible que desee inyectar ciertos valores en su código, por ejemplo, la versión de la compilación (lo cual puede ser una molestia tener que actualizar manualmente cada vez que compile). El dolor es mayor cuando el sistema de compilación extrae el código de algún sistema de control de versiones. La modificación de valores simples en el momento de la compilación requerirá que cambie un archivo, confirme, compile y luego revertir cada vez que cambie. Estos no son cambios que desee confirmar en su control de versión.

Otros casos de uso útiles relacionados con el sistema de compilación y las configuraciones externas:

  • inyectar estilos / hojas de estilo para una única base de código para diferentes compilaciones
  • inyectando diferentes conjuntos de contenido dinámico (o referencias a ellos) para su base de código único
  • inyectando contexto de localización para diferentes builds / clientes
  • cambiar un URI de servicio web a un servidor de respaldo (cuando el principal se cae)

Actualización: Todos los ejemplos anteriores fueron sobre cosas que no necesariamente requerían dependencias en las clases. Pero puede crear fácilmente casos en los que sea necesario un objeto complejo y una automatización, por ejemplo:

  • Imagina que tienes un sistema en el que controla el tráfico de tu sitio web. Dependiendo del número de usuarios concurrentes, activa / desactiva un mecanismo de registro. Quizás mientras el mecanismo está desactivado, se coloca un objeto de código auxiliar en su lugar.
  • Imagina que tienes un sistema de conferencia web en el que, dependiendo del número de usuarios, deseas cambiar la capacidad de hacer P2P dependiendo del número de participantes

No es necesario que vuelva a compilar su código cada vez que cambie algo en la configuración. Simplificará la implementación y el mantenimiento del programa. Por ejemplo, puede intercambiar un componente con otro con solo 1 cambio en el archivo de configuración.

Puedes insertar una nueva implementación para novia. Así que la nueva hembra puede ser inyectada sin volver a compilar su código.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(Lo anterior supone que Female y HotFemale implementan la misma interfaz de GirlfFriend)

En el mundo .NET, la mayoría de los marcos de IoC proporcionan configuración de código y XML.

StructureMap y Ninject, por ejemplo, usan interfaces fluidas para configurar contenedores. Ya no estás obligado a usar archivos de configuración XML. Spring, que también existe en .NET, se basa en gran medida en los archivos XML, ya que es su interfaz de configuración principal histórica, pero aún es posible configurar contenedores mediante programación.

Facilidad de combinar configuraciones parciales en una configuración completa final.

Por ejemplo, en las aplicaciones web, el modelo, la vista y los controladores normalmente se especifican en archivos de configuración separados. Utilice el enfoque declarativo, puede cargar, por ejemplo:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

O cargue con una interfaz de usuario diferente y algunos controladores adicionales:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

Para hacer lo mismo en código se requiere una infraestructura para combinar configuraciones parciales. No es imposible hacerlo en código, pero ciertamente es más fácil hacerlo usando un marco IoC.

A menudo, el punto importante es who está cambiando la configuración después de escribir el programa. Con la configuración en el código, usted asume implícitamente que la persona que lo cambia tiene las mismas habilidades y acceso al código fuente, etc. que el autor original.

En sistemas de producción es muy práctico extraer algunos subconjuntos de configuraciones (por ejemplo, la edad en tu ejemplo) a un archivo XML y permitir, por ejemplo, el administrador del sistema o personal de soporte técnico para cambiar el valor sin otorgarle el poder completo sobre el código fuente u otras configuraciones, o simplemente para aislarlos de las complejidades.

Desde una perspectiva de primavera, puedo darte dos respuestas.

Primero, la configuración XML no es la única forma de definir la configuración. La mayoría de las cosas se pueden configurar usando anotaciones y las cosas que se deben hacer con XML son la configuración del código que no se está escribiendo de todos modos, como un grupo de conexiones que se está utilizando desde una biblioteca. Spring 3 incluye un método para definir la configuración DI utilizando Java similar a la configuración DI enrollada a mano en su ejemplo. Por lo tanto, usar Spring no significa que tenga que usar un archivo de configuración basado en XML.

En segundo lugar, Spring es mucho más que un marco DI. Tiene muchas otras características, incluyendo la gestión de transacciones y AOP. La configuración de Spring XML mezcla todos estos conceptos. A menudo, en el mismo archivo de configuración, estoy especificando las dependencias de los beans, la configuración de las transacciones y agregando los beans de sesión que en realidad se manejan usando AOP en segundo plano. Me parece que la configuración XML proporciona un mejor lugar para administrar todas estas características. También creo que la configuración basada en anotaciones y la configuración XML se amplían mejor que la configuración basada en Java.

Pero veo su punto y no hay nada de malo en definir la configuración de inyección de dependencias en Java. Normalmente lo hago yo mismo en pruebas unitarias y cuando trabajo en un proyecto lo suficientemente pequeño como para no haber agregado un marco DI. Normalmente no especifico la configuración en Java porque para mí ese es el tipo de código de plomería que estoy tratando de evitar escribir cuando elegí usar Spring. Sin embargo, esa es una preferencia, no significa que la configuración XML sea superior a la configuración basada en Java.

Spring también tiene un cargador de propiedades. Utilizamos este método para establecer variables que dependen del entorno (por ejemplo, desarrollo, pruebas, aceptación, producción, ...). Esto podría ser, por ejemplo, la cola para escuchar.

Si no hay razón por la cual la propiedad cambiaría, tampoco hay razón para configurarla de esta manera.

Su estuche es muy simple y, por lo tanto, no necesita un contenedor IoC (Inversión de control) como Spring. Por otro lado, cuando se programa a interfaces, no a implementaciones " (que es una buena práctica en OOP), puede tener un código como este:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(tenga en cuenta que el tipo de myService es IService, una interfaz, no una implementación concreta). Ahora puede ser útil dejar que su contenedor IoC proporcione automáticamente la instancia concreta correcta de IService durante la inicialización: cuando tiene muchas interfaces y muchas implementaciones, puede ser complicado hacerlo manualmente. Los principales beneficios de un contenedor IoC (marco de inyección de dependencias) son:

  • Configuración externa de mapeo entre interfaces y sus implementaciones concretas
  • El contenedor IoC maneja algunos problemas difíciles como resolver gráficos de dependencia complicados, administrar la vida útil de los componentes, etc.
  • Se ahorra tiempo de codificación porque proporciona asignaciones de forma declarativa, no en un código de procedimiento
  • El principio de inversión de control permite realizar pruebas de unidad fácilmente porque puede reemplazar implementaciones reales con falsas (como reemplazar la base de datos SQL con una en memoria)

La inicialización en un archivo de configuración XML simplificará su trabajo de depuración / adaptación con un cliente que tiene su aplicación implementada en sus computadoras. (Porque no requiere recompilación + reemplazo de archivos binarios)

Una de las razones más atractivas es la " Principio de Hollywood " ;: don ' No nos llames, nosotros te llamamos. No se requiere un componente para realizar las búsquedas a otros componentes y servicios en sí; En su lugar, se le proporcionan automáticamente. En Java, esto significa que ya no es necesario realizar búsquedas JNDI dentro del componente.

También es mucho más fácil probar un componente por separado: en lugar de darle una implementación real de los componentes que necesita, simplemente utiliza simulacros (posiblemente generados automáticamente).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top