2008-09-19 10 views
12

¿Puede alguien explicarme las ventajas de usar un contenedor IOC simplemente codificando la implementación predeterminada en un constructor predeterminado?Constructor por defecto versus contenedor IOC

En otras palabras, ¿qué hay de malo en este código?

public class MyClass 
{ 
    private IMyInterface _myInterface; 

    public MyClass() 
    { 
     _myInterface = new DefaultMyInterface(); 
    } 

    public MyClass(IMyInterface myInterface) 
    { 
     _myInterface = myInterface; 
    } 
} 

Por lo que puedo decir, esta clase admite la inyección del constructor lo suficiente para que la prueba de la unidad y la burla se hagan fácilmente. Además de eso, el constructor predeterminado elimina la carga computacional del contenedor IOC (sin mencionar que todo el proceso es mucho más transparente).

Las únicas ventajas que puedo ver al usar un contenedor IOC es si necesita cambiar la implementación de sus interfaces con frecuencia. ¿Me estoy perdiendo de algo?

Respuesta

12

La idea de IoC es delegar parte de la funcionalidad de su componente en otra parte del sistema. En el mundo de IoC, tiene componentes que no se conocen entre sí. Su ejemplo infringe esto, ya que está creando un acoplamiento estricto entre MyClass y alguna implementación de IMyInterface. La idea principal es que su componente no tiene conocimiento acerca de cómo se usará. En su ejemplo, su componente hace algunas suposiciones sobre su uso.

En realidad, este enfoque puede funcionar, pero mezclar IoC e inicialización explícita de objetos no es una buena práctica de OMI.

IoC le da un acoplamiento flojo mediante la realización de encuadernación tardía por el precio de la claridad del código. Cuando agrega un comportamiento adicional a este proceso, hace las cosas aún más complicadas y puede dar lugar a errores cuando algunos componentes pueden recibir objetos con comportamientos no deseados o imprevistos.

0

No veo por qué su técnica de codificación rígida de la implementación predeterminada no se pudo usar junto con un contenedor IOC. Simplemente, las dependencias que no especifiques en la configuración tomarían la implementación predeterminada.

¿O me está faltando algo?

0

Una razón por la que es posible que desee utilizar un Contenedor de IOC sería para facilitar la configuración tardía de su software.

Digamos, por ejemplo, que proporciona varias implementaciones de una interfaz particular: el cliente (o su equipo de servicios profesionales) puede decidir cuál usar modificando el archivo de configuración de IOC.

4

Elija un lado :)

En resumen, se recomienda IOC. El problema con el código es que no puedo cambiar la implementación predeterminada de la dependencia sin volver a compilar el código como lo ha indicado al final. IOC le permite cambiar la configuración o composición de su objeto en un archivo externo sin recompilación.
El COI asume la responsabilidad de "construcción y montaje" del resto del código. El propósito de IOC no es hacer que su código sea comprobable ... es un efecto secundario agradable. (Al igual que el código TDDed conduce a un mejor diseño)

1

Además del acoplamiento flojo, un IoC reducirá la duplicación de código. Cuando utiliza un IoC y desea cambiar la implementación predeterminada de su interfaz, debe cambiarlo en un solo lugar. Cuando utiliza contructors predeterminados para inyectar la implementación predeterminada, debe cambiarla en todos los lugares donde se usa la interfaz.

2

No hay nada de malo con este código y aún puede usarlo con marcos de inyección de dependencia como Spring y Guice.

Muchos desarrolladores ven el archivo de configuración XML de Spring como una ventaja sobre las dependencias de cableado dentro del código, ya que puede cambiar las implementaciones sin necesidad de un paso de compilación. Este beneficio en realidad se realiza en situaciones donde ya tiene varias implementaciones compiladas en su ruta de clase y desea elegir la implementación en el momento del despliegue. Puede imaginar una situación en la que un componente es provisto por un tercero después de la implementación. Del mismo modo, puede haber un caso en el que desee enviar implementaciones adicionales como un parche después de la implementación.

Pero no todos los marcos DI usan la configuración XML. Google Guice, por ejemplo, tiene módulos escritos como clases de Java que deben compilarse como cualquier otra clase de Java.

Entonces, ¿cuál es la ventaja de DI si incluso necesita un paso de compilación? Esto nos lleva de vuelta a su pregunta original. Veo las siguientes ventajas:

  1. Enfoque estándar de DI durante toda la aplicación.
  2. Configuración claramente separada de otra lógica.
  3. Posibilidad de inyectar proxies. El resorte, por ejemplo, le permite realizar el manejo de transacciones declarativas inyectando proxies en lugar de su implementación
  4. Reutilización más fácil de la lógica de configuración. Cuando usa DI de manera extensiva, verá un complejo árbol de dependencias que evoluciona con el tiempo. Administrarlo sin una capa de configuración claramente separada y soporte de marco puede ser una pesadilla. Los marcos DI hacen que sea fácil reutilizar la lógica de configuración a través de la herencia y otros medios.
1

Además de los otros comentarios, se podría argumentar el principio SECO (No repetir) en estos casos. Es redundante tener que poner ese código de construcción predeterminado en cada clase. También presenta el manejo especial de casos donde no es necesario que exista ninguno.

2

La única preocupación que tengo es (1) si su dependencia de servicio predeterminada tiene otra dependencia de servicio/secundaria (y así sucesivamente ... su DefaultMyInterface depende de ILogger) y (2) necesita aislar la primera dependencia de servicio del segundo (necesita probar DefaultMyInterface con un stub ILogger). En ese caso, evidentemente necesitará perder la "nueva DefaultMyInterface" predeterminada y en su lugar hacer una de las siguientes: (1) inyección de dependencia pura o (2) localizador de servicio o (3) container.BuildUp (new DefaultMyInterface());

Algunas de las preocupaciones de otros carteles enumerados pueden no ser justas a su pregunta. No estabas preguntando acerca de múltiples implementaciones de "producción". Usted está preguntando acerca de las pruebas unitarias de . En el caso del testado de unidades, su enfoque, con mi primera advertencia, parece legítimo; Yo también consideraría usarlo en casos simples de prueba unitaria.

Del mismo modo, un par de personas que respondieron expresaron su preocupación por la repitencia. Tampoco me gusta la repetición, pero si (1) su implementación predeterminada es su predeterminada (YAGNI: no tiene planes de cambiar la predeterminada) y (2) no cree que la primera advertencia que establecí aplique y (3) prefiera el enfoque de código más simple que haya compartido, entonces no creo que esta forma particular de repitición sea un problema.

Cuestiones relacionadas