2010-06-10 4 views
6

Пытаясь выяснить, как лучше обрабатывать следующий сценарий:Dependency Injection и завод

Предположим RequestContext класс, который имеет зависимость для внешней службы, такие как:

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

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

Какого рода зависимость должен ли я требовать в классе, который в конечном итоге будет создавать экземпляр RequestContext? Это может быть ServiceFactory<IWeatherService>, но это не кажется правильным, или я мог бы создать IRequestContextFactory для него вдоль линий:

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); 
    } 
} 

А затем пройти через IRequestContextFactory инъекции конструктора.

Это похоже на хороший способ сделать это, но проблема с этим подходом заключается в том, что я считаю, что это препятствует обнаружению (разработчики должны знать о фабрике и реализовывать ее, что на самом деле не очевидно).

Есть ли лучший/более доступный способ, который мне не хватает?

ответ

5

Красота свободной связи состоит в том, что мы можем постоянно скрыть предыдущие детали.

С точки зрения потребителя IRequestContext существование RequestContext и его зависимостей - это только деталь реализации. Из-за Liskov Substitution Principle, потребитель должен иметь дело только с 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... 
} 

Только приложения Composition Root вам нужно, наконец, провод все вместе. Ниже приведен эскиз подхода DI-подхода Бедняка:

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

Интересно, я не думал о том, чтобы вводить RequestContext напрямую, потому что его параметры будут различаться при каждом запросе страницы (ASP.NET MVC). Было бы неплохо использовать NInject для правильного создания класса для меня, например, в строку запроса? Или я бы настроил NInject на использование фабрики, которая возвращает экземпляр, но на базовом уровне просто вводит RequestContext? – andreialecu

+0

Я еще не знаю Ninject достаточно хорошо, чтобы ответить на специфику этого, но если он не поддерживает это напрямую, вы всегда можете реализовать эту небольшую часть самостоятельно, используя абстрактную фабрику, введенную в потребитель более высокого уровня. –

0

Заводская схема - известный, документированный и используемый метод. Если вы заинтересованы в том, чтобы другие разработчики не были в курсе, добавьте ссылку на wikipedia's factory pattern page в (xml) документацию в коде.

Кроме того, убедитесь, что вы назвали свои фабрики согласованно - Microsoft, похоже, как суффикс провайдера.

+0

+1 для суффикса «Поставщик». Нужно реорганизовать мои заводы. :) – andreialecu

+1

-1 для «Провайдера». Знаете ли вы, _why_ они суффикс «Провайдер»? Dont слепо принять его только потому, что MS использовать его. это может быть по совершенно другой причине. –

+4

http://msdn.microsoft.com/en-us/library/ms972319.aspx указывает, что они используют Провайдер, чтобы указать класс, расширяющий ProviderBase, который использует модель поставщика ASP.NET. Только при таких обстоятельствах суффикс провайдера был бы уместным. –