¿Cuáles son los beneficios de los envases de inyección de dependencia?


104

Entiendo los beneficios de la inyección de dependencia en sí. Tomemos Spring, 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>

en comparación con el antiguo código Java simple, 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 entendido por cualquiera que sólo conozca Java. Entonces, ¿cuál es el propósito principal de un marco de inyección de dependencia? (o un fragmento de código que muestre 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 de IoC decida usarla automáticamente, se romperá después de que aparezca una segunda implementación. Y si intencionalmente solo hay una posible implementación de una interfaz, entonces no es necesario inyectarla.

Sería realmente interesante ver una pequeña parte de la configuración para IoC que muestra sus beneficios. He estado usando Spring por un tiempo y no puedo proporcionar tal ejemplo. Y puedo mostrar líneas simples que demuestran los beneficios de hibernate, dwr y otros marcos que uso.


ACTUALIZACIÓN 2:
Me doy cuenta de que la configuración de IoC se puede cambiar sin volver a compilar. ¿Es realmente tan buena idea? Puedo entender cuando alguien quiere cambiar las credenciales de la base de datos sin volver a compilar; puede que no sea un desarrollador. En su práctica, ¿con qué frecuencia alguien más que no sea el 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 los que no son desarrolladores, probablemente querrá facilitarles la vida y proporcionar un archivo de configuración más simple.


ACTUALIZACIÓN 3:

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

¿Qué tiene de bueno hacerla extenuante? No hace que todo su código sea externo, aunque definitivamente puede hacerlo, solo colóquelo en el archivo ClassName.java.txt, lea y compile manualmente sobre la marcha, wow, evitó volver a compilar. ¿Por qué debería evitarse la compilación?

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, declaro solo una vez un mapeo entre una propiedad de bean y una columna de base de datos e hibernate usa este mapeo mientras carga, guarda, construye 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 verlo.

El principio de inversión de control permite una prueba unitaria sencilla porque puede reemplazar implementaciones reales con falsas (como reemplazar la base de datos SQL por una en memoria)

Entiendo los beneficios de la inversión de control (prefiero llamar al patrón de diseño discutido 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). Estaba preguntando por qué alguien necesita algo más que un lenguaje de programación para ello. Definitivamente puedo reemplazar implementaciones reales con falsas usando código. Y este código expresará lo mismo que la configuración: solo inicializará 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 la configuración de código 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 el mapeo entre la propiedad del bean y la columna DB se usa para guardar, cargar, construir consultas de búsqueda, etc. La configuración de Spring DI se puede traducir fácilmente a configurando el código, como al principio de esta pregunta, ¿no es así? Y se usa solo para la inicialización del bean, ¿no es así? Lo que significa que un enfoque declarativo no agrega nada aquí, ¿verdad?

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


ÚLTIMA ACTUALIZACIÓN:
Chicos, muchas respuestas me dicen sobre la inyección de dependencia, lo cual SÉ QUE ES BUENO. La pregunta es sobre el propósito de la configuración DI en lugar de inicializar el código; tiendo a pensar que la inicialización del código es más corta y clara. La única respuesta que he obtenido 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.


21
Finalmente alguien tuvo el coraje de hacer esta pregunta. ¿Por qué querría evitar la recopilación cuando su implementación cambia a costa de sacrificar (o al menos degradar) el soporte de IDE / herramienta?
Christian Klauser

3
Parece que el título no es del todo correcto. El autor ha dicho que los contenedores IOC están bien, pero parece tener problemas con el uso de la configuración XML en lugar de la configuración mediante código (y también es justo). Sugeriría quizás "¿Cuáles son los beneficios de configurar contenedores IOC a través de XML u otros enfoques sin código?"
Orion Edwards

Los ejemplos de @Orion que proporcioné (con hombres y mujeres) no requieren ningún contenedor de COI. Estoy bien con el COI; usar el contenedor, ya sea que esté configurado usando XML o no, sigue siendo una pregunta abierta para mí.
Pavel Feldman

@Orion 2: Si bien utilizo alguna forma de IOC en la mayoría de los proyectos, algunos de ellos se benefician del contenedor de IOC tanto como del contenedor de asignación variable o del contenedor de declaraciones If; el lenguaje es suficiente para mí. No tengo problemas para recompilar los proyectos en los que estoy trabajando y tener el código de inicialización de desarrollo / prueba / producción convenientemente separado. Así que para mí el título está bien.
Pavel Feldman

Veo problemas con la muestra. Uno de los principios son los servicios de inyección, no los datos
Jacek Cz

Respuestas:


40

Para mí, una de las principales razones para usar un IoC (y hacer uso de una 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. Examen de la unidad
  2. Pruebas de integración
  3. Prueba de caja negra

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

Si alguno de sus escenarios de prueba requiere que cambie la configuración (es decir, utilizar otro componente para imitar una integración bancaria o hacer una carga de rendimiento), esto se puede manejar fácilmente (esto se incluye en los beneficios de configurar el lado DI de un Sin embargo, IoC.

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

Producción

Como desarrollador, usted no tiene (y no debería) tener el control del entorno de producción (en particular cuando su aplicación se distribuye a varios clientes o sitios separados), para mí, este es el beneficio real de usar tanto una configuración de IoC como externa , ya que depende del soporte de infraestructura / producción modificar y ajustar el entorno en vivo sin tener que volver a los desarrolladores y realizar pruebas (costo más alto cuando todo lo que quieren hacer es mover un componente).

Resumen

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

  • La aplicación se distribuye a varios sitios / clientes donde los entornos serán diferentes.
  • Control / entrada de desarrollo limitado sobre el entorno de producción y la configuración.
  • Escenarios de prueba.

En la práctica, descubrí que incluso al desarrollar algo sobre el que tienes control sobre el entorno en el que se ejecutará, con el tiempo es mejor darle a otra persona las capacidades para cambiar la configuración:

  • Al desarrollar, no sabe cuándo cambiará (la aplicación es tan útil que su empresa se la vende a otra persona).
  • No quiero quedarme atascado cambiando el código cada vez que se solicita un pequeño cambio que podría haberse manejado configurando y usando un buen modelo de configuración.

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


14

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, para que DI funcione, es necesario otro ingrediente, el de crear interfaces de objetos. Combinando estos dos potentes patrones de diseño, los ingenieros de software se dieron cuenta rápidamente de que podían crear código flexible y débilmente 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 fundamental para la mayor parte de la actualidad '

Un lenguaje debe proporcionar un buen soporte tanto para las técnicas normales de programación orientada a objetos como para las interfaces de objetos y la reflexión de objetos (por ejemplo, Java y C #). Si bien puede crear programas usando patrones DI en sistemas C ++, su falta de soporte de reflexión dentro del lenguaje propiamente dicho 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 a interfaces bien definidas, lo que permite que los objetos separados cuya configuración sea manejada por una plataforma de aplicación adecuada se conecten 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 implementen las interfaces esperadas por la lógica de su aplicación.
  3. El código DI es más flexible. Es un código innatamente acoplado libremente, hasta un extremo. Esto le permite al programador 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 los 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 interés en el sentido de que todos los problemas de inicialización de objetos y gestión de interdependencia de objetos pueden ser manejados por el servidor de aplicaciones.
  6. Tenga en cuenta que no se requiere configuración externa para usar el patrón DI, para interconexiones simples, a menudo es adecuado un pequeño objeto constructor. Existe una compensación en la flexibilidad entre los dos. Un objeto constructor 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, teniendo cuidado de que el control de grano fino a pequeña escala sobre la construcción del objeto, como se expresa 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 objetivo de los sistemas DI. Su capacidad para mezclar y combinar objetos de código como una serie de ajustes de configuración le permite construir sistemas complejos utilizando código 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 correctamente factorizada. Con algo de práctica y mucha autodisciplina, la mayoría de los profesionales de DI descubren que pueden construir sistemas que tienen una cobertura de prueba del 100% del código de la aplicación. Este único punto es extraordinario. Esta no es una cobertura de prueba del 100% de una pequeña aplicación 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 capacidad de prueba.

Tiene razón en que una aplicación de solo decenas 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, como ocurre con los patrones de diseño más poderosos, las ganancias 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 de comprender. Si bien la configuración de Xml no está 'comprobada en tiempo de compilación', todos los servicios de aplicación que este autor conoce proporcionará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 comprobando que el objeto A a inyectar implemente la interfaz requerida por el objeto B para todas las inyecciones de objetos configuradas.


4
comprender los beneficios de la DI. No entiendo qué beneficios agrega la configuración XML externa en comparación con la configuración del código que hace lo mismo. Los beneficios que mencionó los proporciona el patrón de diseño DI. La pregunta era sobre los beneficios de la configuración DI en comparación con el código de inicialización simple.
Pavel Feldman

> La configuración externa también es una separación ... La separación de la configuración es el corazón de DI, lo cual es bueno. Y puede realizar el domo utilizando código de inicialización. ¿Qué agrega cfg en comparación con la inicialización del código? Para mí, parece que cada línea de cfg tiene una línea de código de inicialización correspondiente.
Pavel Feldman

7

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

Simplifican el código muchas veces, pero también tienen una sobrecarga en la complejidad que hace que rastrear problemas sea bastante difícil (he visto estos problemas de primera mano, y me sentiría mucho más cómodo tratando con Java puro).

Supongo que depende un poco del estilo y con lo que se sienta cómodo ... ¿le gusta volar su propia solución y tener la ventaja de conocerla al revés, o confiar en soluciones existentes que pueden resultar difíciles cuando la configuración no lo es? ¿Es justo? Todo es una compensación.

Sin embargo, la configuración XML es algo que me molesta un poco ... trato de evitarlo a toda costa.


5

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 código en sí 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 puede leerse en una GUI o alguna otra herramienta y manipularse fácilmente de forma pragmática. ¿Cómo harías eso con el ejemplo de código?

Constantemente estoy factorizando 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 como datos; debería ser obvio que hacerlo en código es simplemente incorrecto debido a la repetición.


tiene sentido, no lo pensé en esta perspectiva
Pavel Feldman

7
por otra parte, la gente a menudo va en sentido contrario e intenta poner lógica en los datos, lo que solo significa que terminas codificando tu aplicación en un lenguaje de programación deficiente
Casebash

@Casebash Ese es un punto de vista interesante. Me interesaría increíblemente un ejemplo. Encuentro que cualquier cosa que pueda mover a los datos ayuda. También encuentro que si hago exactamente lo que dices, el lenguaje mejora porque es un DSL, pero incluso entonces se necesita una seria justificación para crear un lenguaje completamente nuevo.
Bill K

1
"Cada vez que puede cambiar su código a datos, está dando un paso en la dirección correcta". Bienvenido al anti-patrón Soft Coding.
Raedwald

@Raedwald De lo que estás hablando es de externalización, lo cual puede ser realmente difícil si no sabes lo que estás haciendo (y la razón por la que alguien incompetente lo intentó, falló y lo llamó un anti-patrón). Ejemplos más positivos serían Inyección, iteradores , casi cualquier cosa con anotaciones, cualquier cosa que se inicialice con matrices. La mayoría de las grandes estructuras de programación son un intento de separar las diferencias en su código y combinar lo que queda, conduciéndolo con algo que se pueda agrupar y administrar mejor.
Bill K

3

La razón para usar un contenedor DI es que no es necesario tener mil millones de propiedades preconfiguradas en su código que son simplemente getters y setters. ¿Realmente desea codificar todos aquellos con la nueva X ()? Claro, puede tener un valor predeterminado, pero el contenedor DI permite la creación de singletons, lo cual es extremadamente fácil y le permite concentrarse en los detalles del código, no en la tarea miscelánea de inicializarlo.

Por ejemplo, Spring le permite implementar la interfaz InitializingBean y agregar un método afterPropertiesSet (también puede especificar un "método init" para evitar acoplar su código a Spring). Estos métodos le permitirán asegurarse de que cualquier interfaz especificada como un campo en su instancia de clase esté configurada correctamente al inicio, y luego ya no tendrá que verificar nulos sus getters y setters (suponiendo que permita que sus singletons permanezcan seguros para subprocesos) ).

Además, es mucho más fácil realizar inicializaciones complejas con un contenedor DI en lugar de hacerlo usted mismo. Por ejemplo, ayudo a usar 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 predeterminados de XFire definidos en su esquema de beans de Spring. Entonces, si estuviéramos usando Spring para configurar los servicios, los beans podrían haberse usado. 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 cambio real que necesitaba hacer requería que sobrecargara una sola clase.

Pero, gracias al archivo services.xml, tuve que crear cuatro clases nuevas, estableciendo sus valores predeterminados de acuerdo con sus valores predeterminados en los archivos de configuración de Spring en sus constructores. Si hubiéramos podido usar la configuración de Spring, podría haber 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
    }
}

Entonces, el resultado neto es que se tuvieron que agregar cuatro clases Java adicionales, en su mayoría inútiles, al código base para lograr el efecto que lograron una clase adicional y alguna información de contenedor de dependencia simple. Esta no es la "excepción que prueba la regla", esta ES la regla ... manejar las peculiaridades en el código es mucho más limpio cuando las propiedades ya están provistas en un contenedor DI y simplemente las está cambiando para adaptarse a una situación especial, lo que ocurre con mayor frecuencia.


3

Tengo tu respuesta

Obviamente, existen compensaciones en cada enfoque, pero los archivos de configuración XML externalizados son útiles para el desarrollo empresarial en el que se utilizan sistemas de compilación para compilar el código y no su IDE. Al usar 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 (que podría ser doloroso tener que actualizar manualmente cada vez que compila). El dolor es mayor cuando su sistema de compilación extrae código de algún sistema de control de versiones. La modificación de valores simples en tiempo de compilación requeriría que cambie un archivo, lo confirme, compile y luego revertir cada vez para cada cambio. Estos no son cambios que desee realizar en su control de versiones.

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
  • inyectar diferentes conjuntos de contenido dinámico (o referencias a ellos) para su base de código único
  • inyectar contexto de localización para diferentes compilaciones / clientes
  • cambiar un URI de servicio web a un servidor de respaldo (cuando el principal deja de funcionar)

Actualización: Todos los ejemplos anteriores se referían a cosas que no necesariamente requerían dependencias de clases. Pero puede crear fácilmente casos en los que se necesitan tanto un objeto complejo como la automatización, por ejemplo:

  • Imagina que tienes un sistema en el que monitorea el tráfico de tu sitio web. Dependiendo del número de usuarios concurrentes, enciende / apaga un mecanismo de registro. Quizás mientras el mecanismo está apagado, se coloca un objeto auxiliar en su lugar.
  • Imagine que tiene un sistema de conferencias web en el que, según el número de usuarios, desea cambiar la capacidad de hacer P2P según el número de participantes

+1 para resaltar el aspecto empresarial en la parte superior. Probar código heredado mal escrito a veces puede ser una pesadilla de días.
Richard Le Mesurier

2

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.


¿despliegue? probablemente ... mantenimiento del despliegue? probablemente ... mantenimiento de código? Tiendo a pensar que no ... depurar a través de frameworks tiende a ser un gran dolor de cabeza, y los pojos son mucho más fáciles de manejar en ese sentido.
Mike Stone

1
Mike, no dije nada sobre el código. Todos sabemos que la configuración XML apesta :)
aku

Hmm ... ¿con qué frecuencia cambias componentes sin recompilar y para qué? Entiendo que si alguien cambia las credenciales de la base de datos y no quiere volver a compilar el programa, es posible que no sea él quien lo desarrolle. Pero difícilmente puedo imaginarme a alguien más que al desarrollador cambiando la configuración de primavera
Pavel Feldman

Pavel generalmente esta situación ocurre cuando tienes que implementar un programa en cientos de clientes. En tal situación, es mucho más fácil cambiar la configuración que implementar una nueva versión del producto. Tienes razón al decir sobre los desarrolladores. Por lo general, el desarrollador crea un nuevo cfg y el administrador lo implementa.
aku

2

Puede insertar una nueva implementación para novia. Por lo tanto, se puede inyectar nueva hembra 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 asume que Female y HotFemale implementan la misma interfaz GirlfFriend)


¿Por qué las modificaciones lógicas sin recompilar se consideran una buena idea?
Pavel Feldman

Definitivamente puedo hacer HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (Jane); Entonces, ¿la única diferencia es que cfg se puede cambiar sin volver a compilar? Parece ser una respuesta común cuando se habla de Spring. ¡¿Por qué?! ¿Por qué es bueno evitar la compilación?
Pavel Feldman

Bueno, puedo probar el código mejor que puedo simular el objeto femenino.
Paul Whelan

@Pavel Feldman: porque si ya tienes la aplicación implementada en el cliente es más fácil.
Andrei Rînea

1

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

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


Es genial que finalmente pueda usar código para lo que se pretendía usar :) ¿Pero por qué necesito algo más que un lenguaje de programación para hacer esas cosas?
Pavel Feldman

Creo que eso se debe a que XML permite cambios en tiempo de ejecución, o al menos, cambios de configuración sin tener que volver a compilar el proyecto.
Romain Verdier

1

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

Por ejemplo, en aplicaciones web, el modelo, la vista y los controladores generalmente 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

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


1

A menudo, lo importante es quién cambia la configuración después de que se escribió el programa. Con la configuración en el código, implícitamente asume que la persona que lo cambia tiene las mismas habilidades y acceso al código fuente, etc., que tenía el autor original.

En los sistemas de producción, es muy práctico extraer algún subconjunto de configuraciones (por ejemplo, la edad en su ejemplo) a un archivo XML y permitir, por ejemplo, al administrador del sistema o al personal de soporte cambiar el valor sin darles el poder total sobre el código fuente u otras configuraciones, o simplemente para aislarlos de las complejidades.


Ese es un punto válido, pero la configuración del resorte a menudo tiende a ser bastante compleja. Si bien es fácil cambiar la edad, sysadmin todavía tiene que lidiar con un archivo xml grande que no necesariamente comprende por completo. ¿No es mejor extraer la parte que se supone que debe configurarse en algo aún más simple que la configuración XML de primavera? Como archivo de propiedades, con una sola línea "age = 23" y no permite que el administrador cambie otros detalles, como nombres de clases, etc., que requieren conocimiento de la estructura interna del programa.
Pavel Feldman

Recientemente estuve trabajando en un proyecto que tenía una mezcla de código Java y XSLT. El equipo era una mezcla de personas que eran fuertes en Java (y quizás menos cómodas trabajando con XML y XSLT); y gente que trabajaba muy bien con XML y XSLT (y menos cómoda con Java). Dado que la configuración iba a ser administrada por el segundo grupo, tenía sentido usar Spring y tener configuraciones XML. En otras palabras, Spring resolvió un problema de división del trabajo en el equipo. No resolvió un problema "técnico"; en el sentido de que la configuración podría haberse hecho fácilmente con código Java.
Dawood ibn Kareem

¿Cuándo sabría el 'personal de soporte' algo sobre tener que cambiar algunas clases que se están creando dentro de un contenedor de inyección de dependencia? ¿Realmente bajo la suposición de que es el trabajo de un desarrollador hacer esto?
Jimbo

Esa es exactamente la razón por la que tiene sentido extraer los valores de configuración (por ejemplo, la URL del sistema con el que se integra): el personal de soporte edita el archivo de propiedades o (en el peor de los casos) el archivo XML, la clase Java compilada sigue siendo la misma.
Miro A.

1

Desde una perspectiva de Spring, 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 mediante anotaciones y las cosas que se deben hacer con XML son la configuración del código que no está escribiendo de todos modos, como un grupo de conexiones que está usando desde una biblioteca. Spring 3 incluye un método para definir la configuración DI usando Java similar a la configuración DI enrollada a mano en su ejemplo. Entonces, 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, incluida la gestión de transacciones y AOP. La configuración de Spring XML combina todos estos conceptos. A menudo, en el mismo archivo de configuración, estoy especificando las dependencias de los beans, la configuración de transacciones y agregando beans con ámbito de sesión que realmente se manejan con AOP en segundo plano. Encuentro que la configuración XML proporciona un mejor lugar para administrar todas estas funciones. 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 dependencia en Java. Normalmente lo hago yo mismo en pruebas unitarias y cuando estoy trabajando 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.


0

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

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


0

Su caso es muy simple y, por lo tanto, no necesita un contenedor IoC (Inversión de control) como Spring. Por otro lado, cuando "programa en interfaces, no en implementaciones" (lo cual 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 de IoC proporcione automáticamente la instancia concreta correcta de IService durante la inicialización; cuando tiene muchas interfaces y muchas implementaciones, puede resultar engorroso hacerlo a mano. Los principales beneficios de un contenedor de IoC (marco de inyección de dependencia) son:

  • Configuración externa de mapeo entre interfaces y sus implementaciones concretas
  • El contenedor de IoC maneja algunos problemas complicados como resolver gráficos de dependencia complicados, administrar la vida útil de los componentes, etc.
  • 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 una prueba unitaria sencilla porque puede reemplazar implementaciones reales con falsas (como reemplazar la base de datos SQL por una en memoria)

0

Inicializar 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)


-2

Una de las razones más atractivas es el " principio de Hollywood ": no nos llame, le llamaremos. No es necesario que un componente realice búsquedas en otros componentes y servicios por sí mismo; 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 de forma aislada: en lugar de darle una implementación real de los componentes que necesita, simplemente usa simulacros (posiblemente generados automáticamente).


Esta respuesta trata sobre la inyección de dependencia. Sé lo que es, sé que es bueno y lo expreso claramente en la primera oración de la pregunta. La pregunta era sobre los beneficios de la configuración DI, en comparación con el código de inicialización simple.
Pavel Feldman

Realmente no responde la pregunta
Casebash
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.