2010-03-26 8 views
23

Solo estoy tratando de entender los principios de IOC.COI - ¿Deberían conectarse las clases utilitarias con métodos estáticos de ayuda con el COI?

Q1: Métodos estáticos - ¿Las clases de utilidades con métodos estáticos de ayuda se deben conectar con IOC?

Por ejemplo, si tengo una clase HttpUtils con varios métodos estáticos, ¿debería intentar pasarla a otras clases de lógica de negocios a través de IOC?

seguir con respecto a esto podría ser:

P2: Singleton - ¿Qué pasa con cosas como el registro en el que puede típicamente tener acceso a ella a través de un Logger.getInstance() tipo de llamada. ¿Normalmente dejarías esto como está, y NO usarías IOC para inyectar el registrador en las clases de negocios que lo necesitan?

Q3: Clases estáticas - Realmente no he usado este concepto, pero ¿hay alguna guía sobre cómo manejarías esto normalmente si te movieras a un enfoque basado en IOC?

Gracias de antemano.

Respuesta

30

Lo curioso de IoC es que los objetos escritos en el estilo generalmente están desacoplados de esos detalles.

Vamos a usar la clase de utilidad como un ejemplo:

public class HttpUtils 
{ 
    public static void DoStuff(int someValue) 
    { 
     // ... 
    } 
} 

En una aplicación enfocada la no-COI, es posible utilizar este método directamente:

public class Foo 
{ 
    public int Value { get; set; } 

    public void DoStuff() 
    { 
     HttpUtils.DoStuff(Value); 
    } 
} 

Sin embargo, que las parejas de la definición de DoStuff directamente a su implementación. COI se esfuerza por divorciarse de ese tipo de detalles, así que en vez definimos la operación por sí sola:

public interface IDoesStuff 
{ 
    void DoStuff(int someValue); 
} 

Entonces, dejamos espacio en Foo para la puesta en práctica de cambiar:

public class Foo 
{ 
    private readonly IDoesStuff _doesStuff; 

    public Foo(IDoesStuff doesStuff) 
    { 
     _doesStuff = doesStuff; 
    } 

    public int Value { get; set; } 

    public void DoStuff() 
    { 
     _doesStuff.DoStuff(Value); 
    } 
} 

Esto desacopla Foo de HttpUtils. El implementador del concepto de DoStuff ahora es un detalle de la configuración, y no una dependencia inherente (como lo es con el método estático).

Observe que Foo no tiene idea si su IDoesStuff es un singleton o no. Esa vida útil es también un detalle de configuración, y no un detalle inherente de Foo.

En resumen, IoC y static son generalmente contradictorios, ya que IoC promueve el cambio y static, por definición, lo previene. Declare sus dependencias en sus constructores, y encontrará que casi nunca tiene la funcionalidad static.

+0

gracias Bryan - ¿Esto significa que podría haber un poco más de sobrecarga del COI construyendo cosas (por ejemplo, registrador) cada vez? También para las clases de tipo utils, me pregunto ¿esto hará que la refactorización sea más difícil a medida que refactoriza sus funciones de ayuda entre las clases de ayuda? (Estoy usando ReSharper) - gracias – Greg

+0

La mayoría de los contenedores IoC permiten algún tipo de alcance. Con esto, me refiero a que indique si su objeto se crea cada vez (de fábrica), creado una vez por contexto (unidad de trabajo), o una vez por aplicación (singleton). Esto significa que puede registrar el registrador de manera que solo se crea una vez. –

+2

En última instancia, desea eliminar las clases de utilidad. Cada método en cada una de esas clases tiene los mismos problemas de acoplamiento que el método 'HttpUtils.DoStuff' anterior. Por ese motivo, no es necesario que el código * any * dependa directamente de los miembros 'static'. En su lugar, tome el cuerpo de 'HttpUtils.DoStuff', póngalo detrás de' IDoesStuff', y elimine completamente el método de 'HttpUtils'. Ahora, cualquier clase que pueda haber llamado el método estático puede aceptar 'IDoesStuff' en su constructor. Viola: ¡ya no es necesario para la clase de utilidad! –

6

Un contenedor IoC suele ser útil para inyectar objetos que tienen estado; o clases o interfaces que tienen más de una implementación, incluso si la segunda implementación es una simulación para fines de prueba. Si ninguno de estos es verdadero, no obtienes nada al inyectarlo.el idioma más común en estos días es tener a tu clase frente a una interfaz que la implementación real y simulada pueda implementar.

1) Métodos estáticos en las clases de ayuda - No, estos no suelen ser inyectados por IoC. Típicamente son utilidades sin estado.

Para utilizar un ejemplo muy simple, no necesita dos versiones de un método de utilidad llamado StringUtils.Reverse(). Solo necesita uno, y puede escribir pruebas fácilmente porque no tiene estado o dependencias, por lo que no hay ningún beneficio para burlarse de él. Ejemplo de prueba:

string reversedString = StringUtils.Reverse("input"); 
Assert.AreEqual("tupni", reversedString) 

Si la utilidad no es realmente sin estado (por ejemplo, depende de HttpContext.Current), entonces usted debe hacer explícita la dependencia mediante la inyección, y no hacer la utilidad estática.

2) Singletons: A menudo sí, se inyectan los singletons. Pero una cosa buena de IoC es que te preocupas menos si solo hay uno de algo o no. Usted gana flexibilidad en la creación de instancias usando IoC. La decisión de tener un tipo particular como singleton o nueva instancia cada vez se convierte en parte de la configuración del contenedor IoC y nada más en el código necesita cambiar.

Así que singleton-hood deja de ser una preocupación separada que tiene que codificarse en la clase (y las clases que tienen varias preocupaciones cuando no es necesario) es una preocupación del contenedor IoC. Ya no codificas la clase "como singleton" con nada especial como un constructor privado y un método public static GetInstance(), solo lo codificas para la preocupación principal, mientras que la configuración del contenedor IoC especifica si es un singleton o no, o en algún lugar en el medio, como una instancia por hilo.

3) Las clases estáticas - son el hogar natural de los métodos estáticos. Considere hacer métodos de extensión de métodos estáticos cuando sea apropiado. No puede inyectar estas clases, ya que no puede crearlas. Usar clases estáticas hace que el código de procedimiento no esté orientado a objetos. Esto no es malo para los pequeños métodos de ayuda, pero si la mayoría del código es así, entonces no está usando las poderosas características OO de la plataforma .Net.

2

Los métodos estáticos por definición no necesitan una instancia. DI/IOC tiene como objetivo satisfacer las interfaces con clases concretas y dado que su clase estática junto con sus métodos estáticos por definición no pueden implementar una interfaz o extender una clase, la pregunta no tiene sentido. No tiene sentido pasar la clase auxiliar porque uno no necesita la instancia para usar los métodos estáticos. Tu código siempre ejecutará los mismos métodos helperr estáticos incluso sin una instancia.

En una aplicación con IOC/DI, uno definiría interfaces y tendría al menos una implementación. Se trata de gestionar instancias y sus dependencias.

0

El dilema surge cuando las clases de utilidad, por ejemplo, necesitan acceso a la base de datos. Mientras que el acceso de db necesita Ioc, la clase de utilidad debe usar Ioc como, por lo que no puede ser estático.

Pero realmente quiero que la clase de utilidad sea estática, así de fácil de consumir. No quiero poblar el constructor de cada clase de consumo que necesita clases de utilidad.

Las clases de consumo pueden no necesitar el acceso a db. Así que no quiero inyectar el accesoador de db y pasarlo también a las clases de utilidades.

Supongo que no hay una solución perfecta por el momento.Un día espero que vayamos un paso más allá, además de la inyección de constructor/propiedad, hay "inyección/configuración de contexto global", o "inyección estática", aplicando Ioc más allá de la creación de objetos.

Piensa, ¿por qué no?

+0

¿Es esta una respuesta o solo un comentario sobre la pregunta? –

Cuestiones relacionadas