Является ли зависимость инъекции шаблоном и, не так ли?
У меня были горячие споры с одним из моих коллег по поводу инъекций зависимости, и я понял, что не знаю всех фактов по этому вопросу.
Итак, возьмите этот код (просто чтобы вы знали, мы используем Castle Windsor)
IPlayerService service = Container.Resolve<IPlayerService>();
Вышеприведенный код, очевидно, является примером DI с использованием IoC.
Однако, см. код ниже (ОБНОВЛЕНИЕ: Предположим, что я передаю ВСЕ внешние зависимости через конструктор):
var playerClient = new PlayerClient();
var playerSkinClient = new PlayerSkinClient();
IPlayerService service = new PlayerService(playerClient, playerSkinClient);
Я утверждаю, что приведенный выше код был примером шаблона DI и что DI может существовать без IoC.
Теперь мой коллега не полностью не согласился с моей мыслью, но он сказал, что приведенный выше код не является примером какой-либо картины, связанной с DI.
-
Итак, можно ли использовать DI как шаблон без каких-либо дополнительных фреймворков?
-
Если это так, является ли приведенный выше код примером?
-
Наконец, что определяет шаблон DI, если он существует, без понятия контейнера.
UPDATE
Сегодня я расскажу об ответах и комментариях более подробно позже, но просто хотел поблагодарить всех за хорошо продуманные ответы и комментарии до сих пор!
Ответы
Ответ 1
В мире Java инъекция зависимостей часто включает в себя структуру, контейнер и т.д. Но для всей этой техники нет необходимости.
Сущность инъекции зависимостей - это класс, который может быть назначен объектами, от которых он зависит, а не с их жестко закодированным в реализации. Если вы можете "вводить" эти "зависимости" извне класса, то у вас есть инъекция зависимости. Рамки могут быть хорошим способом сделать это, но это не требуется.
В мире Python нет культуры фреймворков для инъекций зависимостей, поэтому многие программисты удивляются, о чем идет речь. Для них DI "просто" может передавать объекты или классы в конструкторы.
Чтобы ответить на ваш конкретный вопрос:
-
Да, DI может быть выполнен без рамки.
-
Да, приведенный выше код является примером: PlayerService не знает, откуда взялся PlayerClient или PlayerSkinClient. Они были введены в класс. Обратите внимание, что другие здесь ответили на это "Нет".
-
См. выше.
Ответ 2
По словам Мартина Фаулера, который является чем-то вроде эксперта по этому вопросу, Dependency Injection - это другое название для конкретной реализации абстрактного понятия, известного как Inversion of Control (полная статья).
В своем корне все средства DI: объекты, которые класс зависит от правильной работы, инициализируются и передаются в него извне, а не сам класс, ответственный за получение/инициализацию этих объектов. Специфика того, как это выполняется, выходит за рамки шаблона.
IoC - это одно и то же, но, как говорит Мартин Фаулер, "Inversion of Control" - очень тупой способ описания происходящего.
Лично я не думаю, что "Инъекция зависимостей" намного лучше. Я бы описал это как "правильное использование конструкторов".
Пример не-IoC/non-DI:
class Foo
{
void DoSomething()
{
DbConnection myConnection = new DbConnection(ConfigurationSettings...);
myConnection.ExecuteCommand();
}
}
То же самое с помощью IoC/DI:
class Foo
{
private DbConnection myConnection;
public Foo(DbConnection conn)
{
myConnection = conn;
}
void DoSomething()
{
myConnection.ExecuteCommand();
}
}
Я почтительно не согласен с теми, кто утверждает, что это не настоящий IoC/DI, если у вас нет явного связующего/ассемблера/что-то-вы, который соединяет введенные типы с конкретными реализациями, потому что класс, получающий зависимости, Знаю разницу. Если вы устанавливаете зависимости во внешнем классе или внешнем файле конфигурации, это деталь реализации.
Ответ 3
Итак, можно ли использовать DI как шаблон без каких-либо дополнительных фреймворков?
Да, абсолютно.
Если это так, является ли приведенный выше код примером?
Да, абсолютно.
Наконец, что определяет шаблон DI, если он существует, без понятия контейнера.
Объекту дается все, от чего оно зависит; его вложения в него вводятся.
Ответ 4
-
Да, хотя по сравнению с чем-то вроде PicoContainer - или других действительно крошечных контейнеров, все из которых проверены и хорошо продуманны - вы завершите реализацию одного и того же набора функций в конец.
Лучшим примером этого является Ayende "Создание контейнера IoC в 15 строках" .
-
Пересмотр моего ответа, я перейду к да. Я считаю, что основной когнитивный диссонанс здесь объясняется тем, что разработчики скомпрометировали тот факт, что многие/большинство каркасов DI/IoC предлагают аккуратные способы построения объектов, которые не выглядят как new
, что делает их приверженными идеям IoC.
-
Как уже упоминалось, Мартин Фаулер является каноническим определением и довольно хорошо освещен в другом месте.
Ответ 5
Самое смешное, что первый пример - это вовсе не DI, а пример антивирусная программа Locator Anti-Pattern - ничего вводится.
Ваш собственный пример - это чистый DI - более конкретно реализация шаблона Конструктор Injection.
DI - это не один образец, а набор шаблонов и принципов. Когда мы связываем все зависимости вручную, мы обычно называем это Poor Man DI. Другими словами, контейнеры DI строго необязательны, но настоятельно рекомендуется:)
См. также это описание того, что контейнер DI приносит в таблицу.
Ответ 6
Вы должны прочитать это:
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx
Ответ 7
Это действительно не пример DI.
Причина заключается в том, что вы упорядочиваете зависимости (PlayerClient
и PlayerSkinClient
в вашем случае), вместо того, чтобы иметь для вас зависимые (переданные контейнером при конструировании конкретного IPlayerService
). Это "инверсия управления" - вы вызываете конструктор, а не вызываете его. Это основная причина использования шаблона DI и наличие контейнера, который охватывает, разрешает и помещает зависимости в объекты, которые их запрашивают, является конкретным способом сделать это.
Когда вы позволяете контейнеру управлять этой передачей зависимостей, вам не нужно писать и поддерживать код, который передает зависимости конкретному IPlayerService
. Это позволяет вам делать другие реализации PlayerClient
и PlayerSkinClient
(например, когда вы хотите издеваться над ними для построения тестов) и не нужно обновлять код, который инициализирует IPlayerService
. Вот почему шаблон DI полезен.
Ответ 8
Вот некоторые другие статьи, которые могут привести к некоторым другим важным деталям по этому вопросу в порядке "должно быть прочитано первым":
После того, как я прочитал их, я нашел лучшее понимание предмета.