2010-06-10 16 views
6

Tratando de averiguar cómo manejar mejor el siguiente escenario:La inyección de dependencia y la fábrica

suponga una clase RequestContext que tiene una dependencia a un servicio externo, como por ejemplo:

public class RequestContext : IRequestContext 
{ 
    private readonly ServiceFactory<IWeatherService> _weatherService; 

    public RequestContext(ServiceFactory<IWeatherService> weatherService, UserLocation location, string query) 
    { 
     _weatherService = weatherService; 
     ... 

¿Qué tipo de dependencia ¿Debería requerir en la clase que finalmente instanciará RequestContext? Podría ser ServiceFactory<IWeatherService>, pero eso no parece correcto, o que podría crear un IRequestContextFactory por ella a lo largo de las líneas de:

public class RequestContextFactory : IRequestContextFactory 
{ 
    private readonly ServiceFactory<IWeatherService> _weatherService; 

    public RequestContextFactory(ServiceFactory<IWeatherService> weatherService) 
    { 
     _weatherService = weatherService; 
    } 

    public RequestContext Create(UserLocation location, string query) 
    { 
     return new RequestContext(_weatherService, location, query); 
    } 
} 

y luego pasar el IRequestContextFactory través de la inyección de constructor.

Esto parece una buena manera de hacerlo, pero el problema con este enfoque es que creo que dificulta la detectabilidad (los desarrolladores deben conocer la fábrica e implementarla, lo cual no es realmente evidente).

¿Existe alguna forma mejor/más reconocible de la que me pierdo?

Respuesta

5

La belleza del acoplamiento flojo es que podemos constantemente ocultar los detalles anteriores.

Desde la perspectiva de un consumidor de IRequestContext la existencia de RequestContext y sus dependencias es meramente un detalle aplicación. Debido a la Liskov Substitution Principle, el consumidor sólo tiene que lidiar con IRequestContext:

public class MyClass 
{ 
    private readonly IRequestContext reqCtx; 

    public MyClass(IRequestContext reqCtx) 
    { 
     if (reqCtx == null) 
     { 
      throw new ArgumentNullException("reqCtx"); 
     } 

     this.reqCtx = reqCtx; 
    } 

    // Implement using this.reqCtx... 
} 

Sólo en la aplicación de Composition Root hacer todo lo que necesita para, finalmente, se conectan entre sí. Aquí está un bosquejo del acercamiento de DI de un hombre pobre: ​​

ServiceFactory<IWeatherService> weatherService = 
    new ServiceFactory<IWeatherService>(); 
UserLocation location = new UserLocation; 
string query = "foo"; 

IRequestContext reqCtx = new RequestContext(weatherService, location, query); 

var mc = new MyClass(reqCtx); 
+0

Interesante, no he pensado en inyectar RequestContext directamente porque sus parámetros variarían en cada solicitud de página (ASP.NET MVC). ¿Sería una buena idea usar NInject para crear una instancia adecuada de la clase para mí, por ejemplo, mirando a la cadena de consulta? ¿O podría configurar NInject para usar una fábrica que devuelva una instancia, pero en el nivel básico solo inserte RequestContext? – andreialecu

+0

Todavía no conozco Ninject lo suficiente como para responder a las especificaciones al respecto, pero si no lo admite directamente, siempre puede implementar esta pequeña parte usted mismo utilizando Abstract Factory inyectado en un consumidor de nivel superior. –

0

El patrón de fábrica es un método bien conocido, documentado y usado. Si le preocupa que otros desarrolladores no estén actualizados, coloque un enlace al wikipedia's factory pattern page en la documentación (xml) del código.

Además, asegúrese de ponerle nombre a sus fábricas de forma constante: parece que a Microsoft le gusta el sufijo Proveedor.

+0

+1 para el sufijo "Proveedor". Necesito refactorizar mis fábricas. :) – andreialecu

+1

-1 para 'Proveedor'. ¿sabes por qué tienen el sufijo 'Proveedor'? no lo adopte a ciegas solo porque MS lo use. puede ser por una razón completamente diferente. –

+4

http://msdn.microsoft.com/en-us/library/ms972319.aspx indica que utilizan el proveedor para indicar una clase que extiende ProviderBase que utiliza el modelo de proveedor de ASP.NET. Solo en esas circunstancias, el sufijo del proveedor sería apropiado. –

Cuestiones relacionadas