2010-04-03 29 views
8

Todos nuestros informes se crean a partir de gráficos de objetos que se traducen de nuestros objetos de dominio. Para habilitar esto, tenemos una clase Translator para cada informe, y hemos estado usando Dependency Injection para pasar dependencias.Dependency Injection para objetos que requieren parámetros

Esto funcionó muy bien, y le dió buenos clases estructuradas como esto:

public class CheckTranslator : ICheckTranslator 
{ 
    public CheckTranslator (IEmployeeService empSvc 
         , IPaycheckService paySvc) 
    { 
     _empSvc = empSvc; 
     _paySvc = paySvc; 
    } 

    public Check CreateCheck() 
    { 
     //do the translation... 
    } 
} 

Sin embargo, en algunos casos, la asignación tiene muchas diferentes opciones de agrupación. Como resultado, el c-tor se convertiría en una mezcla de dependencias de clase y parámetros.

public class CheckTranslator : ICheckTranslator 
{ 
    public CheckTranslator (IEmployeeService empSvc 
         , IPaycheckService paySvc 
         , bool doTranslateStubData 
         , bool doAttachLogo) 
    { 
     _empSvc = empSvc; 
     _paySvc = paySvc; 
     _doTranslateStubData = doTranslateStubData; 
     _doAttachLogo = doAttachLogo; 
    } 

    public Check CreateCheck() 
    { 
     //do the translation... 
    } 
} 

Ahora, todavía podemos probarlo, pero ya no funciona realmente con un contenedor IoC, al menos de una manera limpia. Además, ya no podemos llamar a CreateCheck dos veces si la configuración es diferente para cada control.

Aunque reconozco que es un problema, no necesariamente veo la solución correcta. Parece un tanto extraño crear una fábrica para cada clase ... ¿o es esta la mejor manera?

+0

¿Puede explicar "ya no funciona realmente con un contenedor IoC"? ¿Qué contenedor estás usando? –

+1

De alguna manera no logro comprender las maravillas de la inyección de dependencia y por qué es incluso un patrón con su propio nombre. ¿Qué te impide convertir los parámetros de bool en propiedades? –

+2

@Hamish: son parámetros de constructor porque son obligatorios. Al tenerlos en el constructor se impone que estén explícitamente establecidos antes de usar el componente. –

Respuesta

13

Disparado en la oscuridad aquí, pero ¿podría mover esos parámetros al método?

En otras palabras:

public Check CreateCheck(bool doTranslateStubData, bool doAttachLogo) 
{ 
    //do the translation... 
} 

hacer esas parámetros tienen que ser pasado a través de la constructora?

(Nota: si su respuesta a esto es "hay demasiados métodos para que sea práctico", entonces parte del problema puede ser que la abstracción es demasiado gruesa).


Otra opción (que es realmente difícil de decir sin entender el modelo de dominio y los patrones de inyección) sería introducir un objeto de parámetro que está a su vez gestionados por el inyector:

public interface ICheckConfiguration 
{ 
    bool AttachLogo { get; } 
    bool TranslateStubData { get; } 
} 

Luego se inyecte esta con el constructor:

public CheckTranslator (IEmployeeService empSvc, IPaycheckService paySvc, 
    ICheckConfiguration config) 
{ 
    // etc. 
} 

Este debería ser suficiente. A continuación, puede crear una clase concreta CheckConfiguration que tome esas dos propiedades bool en su constructor, y configure su contenedor para crear diferentes instancias del objeto parámetro (interfaz) basándose en un parámetro DI de nivel superior.


La última cosa que creo que debo mencionar es que el hecho de que estés usando DI no significa que todo lo tiene que ser gestionado por el contenedor. No es tan malo crear objetos CheckTranslator de forma ad-hoc si solo hay un tipo de "traductor". Mientras el traductor aún dependa de abstracciones, lo cual hace aquí, entonces tal vez no debería inyectarlo en absoluto, solo permita que las clases habilitadas con DI de nivel superior las creen ad-hoc.

+0

Estoy demasiado cansado para editar mi respuesta de nuevo ahora mismo, pero hay una posibilidad más, que es usar Abstract Factory Pattern e inyectar un '[I] CheckTranslatorFactory'. Esa sería una forma válida de crear objetos 'CheckTranslator' o' ICheckTranslator' de un tipo concreto desconocido, con parámetros; en lugar de inyectar la instancia del traductor real, usted inyecta la fábrica y tiene diferentes fábricas responsables de crear diferentes subtipos de traductor. Solo es realmente necesario/útil si tiene la intención de utilizar el polimorfismo para el 'CheckTranslator'. – Aaronaught

+0

Usar ICheckConfiguration es una buena idea. Pase una implementación de patrón nulo para el caso predeterminado y pase una implementación real para otros casos. –

+0

tiene sentido. ¡Gracias! – Andrew

Cuestiones relacionadas