Когда не следует использовать IoC и DI? - PullRequest
33 голосов
/ 01 сентября 2009

Я вижу много статей, в которых говорится о том, насколько хороши IoC и DI, и ни одной о том, почему он не так хорош, потому что он может сделать код более сложным. Я также вижу, что IoC должен быть не в основной части вашего кода, а скорее для библиотек и плагинов. Статьи обычно представляют собой небольшую ссылку на то, как эти два шаблона могут сделать код более сложным, но не очень подробно об этом. Это мой вопрос - где конкретно вы не должны использовать эти шаблоны?

Это хорошая тема: Что такое инверсия контроля? . Если вы посмотрите дальше, есть пост о проверке орфографии и другой пост о том, что IoC, вероятно, не очень полезен, если это только одна проверка орфографии. Как общее правило, следует ли использовать IoC, если у меня когда-либо есть только один конкретный класс для интерфейса? Смысл, у меня есть IMyClass. И тогда есть только конкретный MyClassA, который реализует IMyClass. Зачем мне нужен IoC там?

Если бы у меня были MyClassA, MyClassB и MyClassC, каждый из которых реализовывал IMyClass, это, вероятно, хорошие кандидаты на корректность IoC?

Из той же ветки кто-нибудь знает, что означает этот пост:

  • Смена контроля = Брак
  • Контейнер МОК = Жена

Ответы [ 8 ]

32 голосов
/ 01 сентября 2009

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

ИМХО, Увеличение сложности DI и IoC оплачивается за счет более легкого тестирования и менее связанного кода. Проще выделить проблемы и внести будущие изменения. Вы также можете лучше контролировать его поведение.

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

21 голосов
/ 30 сентября 2009

инверсия контроля = брак

Контейнер МОК = Жена

Брак - это определение известного шаблона - Жена - это реализация этого шаблона; -)

Bernard.

15 голосов
/ 01 сентября 2009

Использование контейнера IoC или нет - это не решение, принимаемое на уровне отдельных классов - в любом проекте вы будете иметь типы, которые создаются и не создаются контейнером.

Сложность компромисса такова:

  • Для небольшого количества компонентов контейнер IoC добавляет некоторые издержки
  • По мере увеличения количества компонентов в приложении:
    • Без контейнера IoC добавление новых компонентов или рефакторинг становится все труднее
    • С контейнером IoC добавление новых компонентов или рефакторинг остаются прежними: вам нужно только беспокоиться о непосредственной зависимости добавляемого или изменяемого компонента.

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

11 голосов
/ 01 сентября 2009

От Проект Замка :

Почему бы мне не использовать его?

Вы не должны использовать Инверсию Контейнер контроля, если вы не знакомы с понятиями, и если вы не осознают проблемы, которые они пытаются решить.

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

6 голосов
/ 01 сентября 2009

Жалобы на IoC легко понять: IoC превращает что-то простое в нечто сложное. Допустим, вы хотели сделать что-то для каждого элемента списка (в псевдокоде):

for each i in list:
    do_something(i)

IoC, по сути, перекладывает ответственность за итерацию цикла на кого-то другого. Таким образом, мы получаем нечто более похожее на это:

ioc = new IocContainer()
ioc.register_callback(do_something)
ioc.go()

Обратите внимание, что даже в этой простой форме код длиннее исходного ... и это не считая реализации IocContainer.

Затем, в своей самой причудливой форме, IocContainer может быть инициализирован статически или статической функцией Main () или где-то еще скрытым, а функции register_callback () вызываются автоматически на основе некоторого другого кода, который перебирает XML-файл. который перечисляет все ваши функции do_something () и (иногда) даже содержимое списков, чтобы перебрать их.

Да, XML-файл сделал вашу программу более настраиваемой! Правильно? Вы можете изменить то, что сделано с вашим списком, просто изменив простой текстовый файл!

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

Для таких вещей, как плагины, может иметь смысл использовать IoC, поскольку логично , чтобы основное приложение контролировало процесс выполнения, и просто попросило плагин о помощи здесь и там. Это называется «предоставлением хуков» и существует намного дольше, чем терминология IoC.

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

Фундаментальное допущение IoC заключается в том, что загрузка данных и циклическая обработка данных как-то затруднительны и должны быть исключены; это предположение просто неверно, потому что в любом случае оно никогда не превышало пары строк (или вы могли бы переместить его в отдельную функцию), и даже если оно сохраняло код, это снижает вашу гибкость.

4 голосов
/ 01 сентября 2009

IoC / DI - это не технологии, а парадигмы. Ваш вопрос похож на вопрос "Когда я не должен использовать объектно-ориентированное программирование?" Это решение больше, чем отдельные единицы вашей кодовой базы.

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

2 голосов
/ 01 сентября 2009

Полагаю, я бы сказал, что простой ответ использует IoC только для объектов, которые вы хотите протестировать.

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

0 голосов
/ 12 августа 2013

Эта статья посвящена вашему вопросу "где конкретно вы не должны использовать эти шаблоны?" и приводит подробные примеры вашего комментария о том, что «эти два шаблона ([IoC и DI]) могут усложнить код»:

http://java.dzone.com/articles/beyond-injection-concerns-ioc.

Подводя итог двум пунктам этой статьи:

  1. Вы не должны использовать IoC / DI там, где важна инкапсуляция.
  2. Вы не должны использовать IoC / DI, если вы не можете продемонстрировать конкретные примеры того, как сложность, добавленная за счет использования IoC / DI, взвешена преимуществами использования IoC / DI.
...