2010-06-03 2 views
4

У меня есть форма поиска, которая может искать в разных провайдерах. Я начал имеющего основание контроллераВнесите различный репозиторий в зависимости от контроллера запроса/вывода и введите репозиторий в зависимости от типа контроллера/ASP.NET MVC

public SearchController : Controller 
{ 

    protected readonly ISearchService _searchService 

    public SearchController(ISearchService searchService) 
    { 
     _searchService= searchService; 
    } 

    public ActionResult Search(...) 
    { 
     // Use searchService to query and return a view. 
    } 

} 

И дочерних контроллеры

TwitterController : SearchController 
{ 
    ... 
} 

NewsController : SearchController 
{ 
    ... 
} 

Я использую StructureMap вставить всю свою зависимость в контроллере. С помощью этой настройки я смог изменить SearchService в зависимости от типа управляемого контроллера.

x.For<ISearchService>().ConditionallyUse(o => 
     { 
      o.TheDefault.Is.OfConcreteType<NewsSearchService>(); 

      o.If(c => c.ParentType == typeof(TwitterController)) 
      .ThenIt.Is.OfConcreteType<TwitterSearchService>(); 

      ... 

     }); 

Это даже позволил мне установить различные виды для каждого контроллера (только поставив соответствующую папку (Twitter, новости ...) и родительский контроллер по-прежнему обработки всего поиска, с помощью простого

return View(results) 

который отображает правильный вид, специфичную для Twitter, новости или другой

Теперь это было круто и выглядел здорово, я одну форму и различные виды отображаются в виде вкладок на одной странице. Вот где это начинает усложняться при таком подходе. форма должна публиковать в/Twitter для поиска в твиттере, в/Новости для поиска в новостях ... что означает, что я должен изменить параметр действия формы в зависимости от того, какая вкладка я есть, и отобразить правильную вкладку, когда форма возвращается в зависимости на .. url? сумасшествие следует.

Если вы уже создали что-то подобное или знаете, что лучше всего подходит для этого, пожалуйста, совет приветствуются.

Теперь я думаю, что у меня было бы меньше боли, используя параметр в форме и проводку на один контроллер. Я думаю о том, чтобы ввести правильный SearchService в зависимости от этого параметра. Какой был бы лучший подход? Я думал об использовании модели связующего,

Так что я бы мой ActionMethod, которые выглядят так:

public ActionResult Search(ISearchService service, Query query) 
{ 
    var results = service.Find(query); 
} 

Но я думаю, что нужно будет сделать вызов, как это в ModelBinder

ObjectFactory.GetInstance(...); 

На основе параметра querystring, который описывает, какой поставщик использовать, и который не кажется мне более изящным. .. Я чувствую себя застрял, помогите :(

ответ

1

Я пытался выяснить, как использовать шаблон абстрактной фабрики, и все равно позволить структуре структуры решить все зависимости моих компонентов.

Я считаю, что именно так я собираюсь его реализовать, но я отправляю это здесь, чтобы получить некоторую обратную связь, если кто-то прочитает это.

Как объясняется в предыдущем ответе, я не хочу строить весь граф объекта в зависимости от того, какой провайдер мне нужен на фабрике Аннотация.

т.е.

class StatServiceFactory : IStatServiceFactory 
{ 
    public IStatService Create(string provider) 
    { 
     switch(provider) 
     { 
      case "blog": 
       return new StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder); 
         //How to resolve the Config, the SearchManager, and BooleanQueryBuilder? 
         //Add more abstract factories? It starts to get messy in my opinion... 
     } 
    } 

} 

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

Structuremap позволяет создавать именованные экземпляры таким образом:

x.For<ISearchManager>().Use<AbcSearchManager>().Named("Abc"); 
x.For<ISearchManager>().Use<DefSearchManager>().Named("Def"); 

Мне нужен способ впрыска контейнера в мою абстрактную фабрику. Я бы, вероятно, упаковал контейнер в оболочку, определенную следующим образом. Это удержит меня от утечки Structuremap в мой проект. Мне не нужна больше, что эти 2 функции в рамках абстрактной фабрики в любом случае, но это не является необходимым:

public interface IContainerWrapper 
{ 
    object GetInstance<T>(); 
    object GetNamedInstance<T>(string key); 
} 

и реализация:

public class ContainerImpl : IContainerWrapper 
{ 
    private readonly Container _container 
    public ContainerImpl(Container container) 
    { 
      _container = container; 
    } 

    ... 
} 

и установка StructureMap для разрешения зависимостей к моей абстрактной фабрике, как, что :

x.For<IContainer>.Use(new ContainerImpl(this)); 
x.For<IFactory>.Use<Factory>() 

Моя фабрика будет тогда гораздо проще и создаст свой экземпляр так:

public class SearchmanagerFactory 
{ 
    private readonly IContainerWrapper _container; 

    public SearchmanagerFactory(IContainerProvider containerProvider) 
    { 
     _container = containerProvider; 
    } 

    public ISearchManager Create(string provider) 
    { 
     //eed to handle the bad input for provider. 
     return (ISearchManager) 
      _container.Resolve<ISearchManager>(provider); 
    } 
} 

Это кажется довольно чистым таким образом :). Мысли?

6

Всякий раз, когда вам нужно варьировать зависимость в зависимости от значения времени выполнения, Abstract Factory является общим решением

Вместо введения ISearchService в контроллерах, впрыснуть в ISearchServiceFactory:

public SearchController : Controller 
{ 
    private readonly ISearchServiceFactory searchServiceFactory; 

    public SearchController(ISearchServiceFactory searchServiceFactory) 
    { 
     if (searchServiceFactory == null) 
     { 
      throw new ArgumentNullException("searchServiceFactory"); 
     } 

     this.searchServiceFactory = searchServiceFactory; 
    } 

    public ActionResult Search(...) 
    { 
     // Use searchServiceFactory to create an ISearchService based on 
     // run-time values, and use it to query and return a view. 
    } 
} 

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

public interface ISearchServiceFactory 
{ 
    ISearchService Create(Query query); 
} 
+0

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

+0

см. Мое другое предложение. Как вы думаете? –

+0

Действительно ли это так, как я должен идти? что бы просто удалить все использование моего IOC ... и я бы подключил все мои компоненты вручную на основе параметра на абстрактной фабрике? –

0

Это более подробный комментарий, чем ответ, чтобы объяснить, почему AbstractFactory кажется сложным.Вот то, что выглядит ближе от реальности:

class StatServiceFactory : IStatServiceFactory 
{ 
    public IStatService Create(string provider) 
    { 
     switch(provider) 
     { 
      case "blog": 
       return new StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder); 
          //How to resolve the Config, the SearchManager, and BooleanQueryBuilder? 
          //Add more abstract factories? It starts to get messy in my opinion... 
     } 
    } 
} 

FacetRepository одинаково для любого провайдера, но изменения SearchManager, изменения ConfigManager и BooleanQueryBuilder является абстрактным классом, с различной реализацией для другого поставщика (поскольку каждый API не использует одно и то же ключевое слово для своих запросов). Все эти зависимости в настоящее время разрешены структурой структуры, основанной на типе контроллера.

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

См. Мое редактирование в конце моего вопроса для другого предложения моей проблемы.

Смежные вопросы