Конструктор по умолчанию против контейнера IOC

StackOverflow https://stackoverflow.com/questions/100922

  •  01-07-2019
  •  | 
  •  

Вопрос

Может ли кто-нибудь объяснить мне преимущества использования контейнера IOC по сравнению с простым жестким кодированием реализации по умолчанию в конструктор по умолчанию?

Другими словами, что не так в этом коде?

public class MyClass
{
    private IMyInterface _myInterface;

    public MyClass()
    {
        _myInterface = new DefaultMyInterface();
    }

    public MyClass(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
}

Насколько я могу судить, этот класс достаточно поддерживает внедрение конструктора, поэтому легко выполнить модульное тестирование и макетирование.В дополнение к этому, конструктор по умолчанию устраняет вычислительные затраты контейнера IOC (не говоря уже о том, что весь процесс становится намного более прозрачным).

Единственное преимущество, которое я вижу в использовании контейнера IOC, — это необходимость часто отключать реализацию своих интерфейсов.Я что-то пропустил?

Это было полезно?

Решение

Идея IoC состоит в том, чтобы делегировать часть функциональности вашего компонента другой части системы.В мире IoC есть компоненты, которые не знают друг о друге.Ваш пример нарушает это, поскольку вы создаете тесную связь между MyClass и некоторой реализацией IMyInterface. Главная идея это твой компонент не имеет знаний о том, как оно будет использоваться.В вашем примере ваш компонент делает некоторые предположения о его использовании.

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

IoC дает вам слабую связь, выполняя позднее связывание за счет ясности кода.Когда вы добавляете в этот процесс дополнительное поведение, это еще больше усложняет ситуацию и может привести к ошибкам, когда некоторые компоненты потенциально могут получить объект с нежелательным или непредсказуемым поведением.

Другие советы

Выбирайте сторону :)

Короче говоря, МОК рекомендуется.Проблема с кодом заключается в том, что я не могу заменить реализацию зависимости по умолчанию без перекомпиляции кода, как вы сказали в конце.IOC позволяет вам изменять конфигурацию или состав вашего объекта во внешнем файле без перекомпиляции.
IOC берет на себя ответственность за «строительство и сборку» остальной части кода.Цель IOC не в том, чтобы сделать ваш код тестируемым...это приятный побочный эффект.(Точно так же, как код TDD приводит к лучшему дизайну)

В этом коде нет ничего плохого, и вы все равно можете использовать его с фреймворками внедрения зависимостей, такими как Spring и Guice.

Многие разработчики рассматривают XML-файл конфигурации Spring как преимущество перед связыванием зависимостей внутри кода, поскольку вы можете переключать реализации без необходимости этапа компиляции.Это преимущество фактически реализуется в ситуациях, когда у вас уже есть несколько реализаций, скомпилированных в вашем пути к классам, и вы хотите выбрать реализацию во время развертывания.Вы можете представить себе ситуацию, когда компонент после развертывания предоставляется третьей стороной.Аналогичным образом может возникнуть ситуация, когда вы захотите отправить дополнительные реализации в виде исправления после развертывания.

Но не все платформы DI используют конфигурацию XML.Например, в Google Guice есть модули, написанные как классы Java, которые необходимо скомпилировать, как любой другой класс Java.

Так в чем же преимущество DI, если вам вообще нужен этап компиляции?Это возвращает нас к вашему первоначальному вопросу.Я вижу следующие преимущества:

  1. Стандартный подход к внедрению зависимостей во всем приложении.
  2. Конфигурация аккуратно отделена от остальной логики.
  3. Возможность внедрения прокси.Например, Spring позволяет вам выполнять декларативную обработку транзакций путем внедрения прокси вместо вашей реализации.
  4. Упрощенное повторное использование логики конфигурации.Если вы активно используете DI, вы увидите сложное дерево зависимостей, развивающееся с течением времени.Управление им без четко выделенного уровня конфигурации и поддержки инфраструктуры может оказаться кошмаром.Платформы DI упрощают повторное использование логики конфигурации посредством наследования и других средств.

Единственное, что меня беспокоит, это (1) если ваша зависимость от службы по умолчанию сама имеет зависимость от другой/вторичной службы (и так далее... ваш DefaultMyInterface зависит от ILogger) и (2) вам необходимо изолировать первую зависимость службы от второй ( необходимо протестировать DefaultMyInterface с помощью заглушки ILogger).В этом случае вам, очевидно, придется потерять «новый DefaultMyInterface» по умолчанию и вместо этого выполнить одно из:(1) чистое внедрение зависимостей или (2) указатель службы или (3)Container.BuildUp(new DefaultMyInterface());

Некоторые опасения, перечисленные другими авторами, могут быть несправедливы по отношению к вашему вопросу.Вы не спрашивали о нескольких «производственных» реализациях.Вы спрашиваете о модульное тестирование. В случае модульного тестирования ваш подход, с учетом моего первого предостережения, кажется законным;Я бы тоже рассмотрел возможность использования его в простых модульных тестах.

Аналогичным образом, несколько респондентов выразили обеспокоенность по поводу повторяемости.Я тоже не люблю повторение, но если (1) ваша реализация по умолчанию действительно ваша по умолчанию (YAGNI:у вас нет планов по изменению значения по умолчанию) и (2) вы не верите, что первое изложенное мною предостережение применимо, и (3) предпочитаете более простой подход к коду, которым вы поделились, тогда я не думаю, что эта конкретная форма повторение - это проблема.

Помимо слабой связи, IoC уменьшит дублирование кода.Когда вы используете IoC и хотите изменить реализацию интерфейса по умолчанию, вам нужно изменить ее только в одном месте.Когда вы используете конструкторы по умолчанию для внедрения реализации по умолчанию, вам придется менять ее везде, где используется интерфейс.

В дополнение к другим комментариям в этих случаях можно было бы привести аргументы в пользу принципа DRY (Не повторяйся).Нет необходимости помещать этот код конструкции по умолчанию в каждый класс.Также введена обработка особых случаев, когда она не требуется.

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

Или я что-то упускаю?

Одной из причин, по которой вы можете использовать IOC-контейнер, является облегчение поздней настройки вашего программного обеспечения.

Скажем, например, вы предоставляете несколько реализаций определенного интерфейса — клиент (или ваша команда профессиональных услуг) может решить, какую из них использовать, изменив файл конфигурации IOC.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top