13

Что-то, что прослушивало меня с тех пор, как я прочитал ответ на другой вопрос о стеке (точное время ускользает от меня сейчас), где пользователь указал что-то вроде «Если вы хотите, Re: Caller Locator, вы делаете это неправильно. «Инъекция зависимостей с помощью Ninject, MVC 3 и с использованием шаблона Locator службы

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

Тем не менее, есть много мест, где я использовал локатор сервисов для разрешения зависимостей в моем проекте. Как только основной пример приходит из моих реализаций ModelBinder.

Пример типичного связующего.

public class FileModelBinder : IModelBinder { 
    public object BindModel(ControllerContext controllerContext, 
          ModelBindingContext bindingContext) { 
     ValueProviderResult value = bindingContext.ValueProvider.GetValue("id"); 

     IDataContext db = Services.Current.GetService<IDataContext>(); 
     return db.Files.SingleOrDefault(i => i.Id == id.AttemptedValue); 
    } 
} 

не реальное осуществление - только быстрый пример

Поскольку реализация ModelBinder требует нового экземпляра, когда Binder является первый просил, это невозможно использовать Dependency Injection на конструктор для этого особая реализация.

Это так во многих моих классах. Другим примером является процесс истечения срока действия кеша, который запускает метод, когда объект кэша истекает на моем веб-сайте. Я запускаю множество запросов к базе данных, а что нет. Там тоже я использую Locator для получения требуемой зависимости.

Другой вопрос, который я имел в последнее время (что я разместил вопрос здесь о) было то, что все мои контроллеры требуется экземпляр IDataContext, который я использовал для DI - но один метод требуются действия другой экземпляр IDataContext. К счастью, Ninject пришел на помощь с именованной зависимостью. Однако это было похоже на клочье, а не на реальное решение.

Я думал, что, по крайней мере, я понял концепцию Разделения забот достаточно хорошо, но, похоже, что-то принципиально неправильно с тем, как я понимаю инъекцию зависимостей и шаблон локатора обслуживания - и я не знаю, что это такое.

Способ, которым я в настоящее время это понимаю, - и это может быть ошибочным, так это то, что, по крайней мере, в MVC ControllerFactory ищет конструктор для контроллера и вызывает сам локатор службы, чтобы получить необходимые зависимости, а затем передает они в. Однако я могу понять, что не все классы и то, что не имеет фабрики для их создания. Так что мне кажется, что какой-то шаблон сервисного локатора допустим ... но ...

  1. Когда это неприемлемо?
  2. Какую модель мне следует искать, когда я должен переосмыслить, как я использую шаблон локатора сервисов?
  3. Является ли моя версия ModelBinder неправильной? Если да, то что мне нужно научиться исправлять?
  4. В другом вопросе в строках этого одного пользователя Mark Seemann рекомендовал абстрактную фабрику - как это соотносится?

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

Я понимаю, что DI не может быть ответом на все, и я могу зайти за борт в том, как я его реализую, однако, похоже, он работает так, как я ожидаю, с Unit Testing, а что нет.

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

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

+0

Я думаю, что вы имеете в виду Марка Симана и это сообщение в блоге: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx –

ответ

14

Рассмотрим следующий пример:

public class MyClass 
{ 
    IMyInterface _myInterface; 
    IMyOtherInterface _myOtherInterface; 

    public MyClass(IMyInterface myInterface, IMyOtherInterface myOtherInterface) 
    { 
    // Foo 

    _myInterface = myInterface; 
    _myOtherInterface = myOtherInterface; 
    } 
} 

С этой конструкции я в состоянии выразить требования зависимостей для моего типа. Сам тип не несет ответственности за знание того, как создавать экземпляры любой из зависимостей, они даются ему (вводятся) каким-либо разрешительным механизмом (обычно это контейнер IoC). Принимая во внимание, что:

public class MyClass 
{ 
    IMyInterface _myInterface; 
    IMyOtherInterface _myOtherInterface; 

    public MyClass() 
    { 
    // Bar 

    _myInterface = ServiceLocator.Resolve<IMyInterface>(); 
    _myOtherInterface = ServiceLocator.Resolve<IMyOtherInterface>(); 
    } 
} 

Наш класс теперь зависит от создания конкретных экземпляров, В этом смысле Service Location можно считать анти-шаблоном, потому что вы не подвергаете зависимостям, но вы разрешаете проблемы, которые можно поймать путем компиляции, чтобы взорваться во время выполнения. (Хорошее чтение - here). Вы скрываете сложности.

Выбор между тем или другим действительно зависит от того, какое ваше здание находится на вершине и предоставляемых услугах. Обычно, если вы создаете приложение с нуля, я бы выбрал DI все время. Он улучшает ремонтопригодность, повышает модульность и упрощает тестирование типов. Но, взяв ASP.NET MVC3 в качестве примера, вы можете легко реализовать SL, как его запекли в дизайне.

Вы всегда можете найти композитный дизайн, в котором вы можете использовать IoC/DI с SL, так же, как с помощью Common Services Locator. Компоненты могут быть подключены через DI, но через SL. Вы даже можете добавить композицию в микс и использовать что-то вроде Managed Extensibility Framework (которая сама поддерживает DI, но также может быть подключена к другим контейнерам IoC или локаторам сервисов). Это большой выбор дизайна, как правило, моя рекомендация для IoC/DI, где это возможно.

Ваш конкретный дизайн Я бы не сказал, это неправильно. В этом случае ваш код не несет ответственности за создание экземпляра самого связующего устройства модели, это зависит от структуры, поэтому вы не можете контролировать этот , но. Использование локатора службы, вероятно, может быть легко изменено для доступа к контейнеру IoC , Но действие разрешения вызова в контейнере IoC ... не считаете ли вы это местоположение службы?

С абстрактным заводским рисунком завод специализируется на создании конкретных типов. Вы не регистрируете типы для разрешения, вы, по существу, регистрируете абстрактный завод и строит любые типы, которые могут потребоваться. С помощью Service Locator он предназначен для , чтобы найти службы и вернуть эти экземпляры. Похоже на конвенциональную точку зрения, но очень по-разному в поведении.

+0

Это в значительной степени, как я его сейчас использую. (Локатор общих служб) Ни один из моих классов не создает собственные зависимости, когда это возможно для меня, чтобы передать их. Последнее предложение - это то, что я просто запутываю, потому что это тот самый вопрос, который я задал себе несколько раз , Я просто ненавижу идею видеть «Решать» повсюду. Это просто * кажется * Я делаю что-то не так ... – Buildstarted

+0

В этой ситуации, вероятно, неизбежно, вы хотите сохранить надежность развязанной реализации и, если у вас нет контроля над созданием этого типа, вариант ... –

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

  • Нет связанных вопросов^_^