Кто-то на Пасущемся подкасте Кода № 68, http://herdingcode.com/herding-code-68-new-year-shenanigans/, заявил, что контейнеры МОК не имели никакого места с Python или JavaScript или словами к тому эффекту. Я предполагаю, что это - расхожее мнение и что оно относится ко всем динамическим языкам. Почему? Что о динамических языках делает контейнеры МОК ненужными?
IoC предоставляет механизм для разрыва связи, которую вы получаете, когда объект вызывает 'new' на другом классе. Эта связь связывает вызывающий объект с инстанцированной реализацией любого интерфейса, который он реализует.
В статических языках, когда вы ссылаетесь на класс по имени (чтобы вызвать new
на нем), нет никакой двусмысленности. Это жесткая связь с конкретным классом.
В динамических языках вызов new X
- это место для "инстанцирования любого класса, определенного как X
в момент выполнения". Это более слабая связь, поскольку она связана только с именем X
.
Это тонкое различие означает, что в динамическом языке обычно можно изменить имя X
, поэтому решение о том, какой класс будет инстанцирован, все еще может быть изменено вне вызывающего класса.
Однако лично я считаю, что у IoC есть два преимущества, которые я не получаю, полагаясь на динамический язык для разрешения инъекций.
Одним из побочных эффектов передачи зависимостей через конструкторы является то, что в итоге вы получаете классы-"строительные блоки", очень развязанные, многократно используемые и легко тестируемые. Они не имеют представления о том, в каком контексте их предполагается использовать, поэтому вы можете использовать их повсюду.
Другой результат - наличие явного кода для выполнения проводки. Правильно выполненный, он четко представляет структуру вашего приложения и его декомпозицию на подсистемы и жизненные циклы. Это заставляет людей явно решать, с каким жизненным циклом или подсистемой они хотят связать свой класс (при написании кода проводки), и концентрироваться на поведении объекта при написании класса.
Как сказал Йорг В. Миттаг. "Эти инструменты не нужны, принципы проектирования - нет". Я считаю, что они не нужны, но если все сделано правильно, то все равно ценны.
Потому что они уже встроены в язык.
Контейнер IoC обеспечивает две вещи:
Динамическое связывание уже является частью динамического языка, а динамический язык уже является динамическим языком. Следовательно, контейнер IoC просто не имеет смысла: язык уже является контейнером IoC.
Другой способ взглянуть на это: что позволяет делать контейнер IoC? Это позволяет вам взять независимые компоненты и связать их вместе в приложение, при этом ни один из компонентов ничего не знает друг о друге. Есть название для объединения независимых частей в приложение: сценарии! (Это в значительной степени определение сценариев.) Многие динамические языки также неплохо справляются с написанием сценариев, поэтому они идеальны в качестве контейнеров IoC.
Обратите внимание, что я не говорю о внедрении зависимостей или инверсии управления. DI и IoC так же важны для динамических языков, как и для статических, по точно таким же причинам. Я говорю о контейнерах IoC и фреймворках DI. Эти инструменты не нужны, принципы проектирования - нет.
Одной из основных особенностей контейнеров IOC является то, что вы можете автоматически «связывать» свои модули вместе во время выполнения. В динамических языках это можно сделать довольно легко без какой-либо сложной логики, основанной на отражении. Однако контейнеры IOC - это полезный шаблон, который понимают многие люди, и иногда может быть полезно использовать один и тот же стиль дизайна. См. эту статью для получения другой точки зрения.
У меня другое мнение. Я думаю, что контейнеры IOC, безусловно, играют роль в динамических языках.
Я не разделяю мнения о том, что динамический язык устраняет необходимость в четко структурированной композиции объектов. Или что динамический язык «предоставляет» ту же функциональность.
Контейнер IOC - это просто инструмент для управления этой организацией.
Даже в динамическом языке я хочу «связать» компоненты вместе. Без жестких зависимостей между этими компонентами. Или, может быть, даже без указания фактического класса реализации для этих компонентов.
Контейнеры IoC действительно позволяют создать композиционный слой в статически типизированных, процедурных/ОО языках.
Этот композиционный слой существует относительно естественно в динамических языках, таких как Python или Javascript (учтите, что Javascript в значительной степени основан на Scheme).
Вероятно, можно привести хороший аргумент, что контейнеры IoC - это просто обобщение паттерна Interpreter.
Herding Code 82 (06.06.10) сравнивает Ruby с .NET и включает подробное обсуждение того, в какой степени .NET требует больше IOC / DI, чем Ruby.