Подтвердить что ты не робот

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

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

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

public class MyClass
{
    private IMyInterface _myInterface;

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

В дополнение к другим комментариям, в этих случаях можно утверждать принцип DRY (Do not Repeat Yourself). Это необходимо для того, чтобы поместить этот код конструкции по умолчанию в каждый класс. Он также внедряет специальную обработку дела, где нет необходимости.

Ответ 7

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

Или я что-то не хватает?

Ответ 8

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

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