Простейшее объяснение того, как работает контейнер DI?
В простых терминах и/или в псевдокоде высокого уровня, как работает контейнер DI и как он используется?
Ответы
Ответ 1
В своей основе DI Container создает объекты на основе сопоставлений между интерфейсами и конкретными типами.
Это позволит вам запрашивать абстрактный тип из контейнера:
IFoo f = container.Resolve<IFoo>();
Для этого требуется, чтобы вы ранее сконфигурировали контейнер для сопоставления из IFoo в конкретный класс, который реализует IFoo (например, Foo).
Это само по себе было бы не особенно впечатляюще, но DI Containers делать больше:
- Они используют Auto-Wiring, что означает, что они могут автоматически определить, что если IFoo сопоставляет карты Foo и IBar с Bar, но Foo имеет зависимость от IBar, он создаст экземпляр Foo с бар, когда вы запрашиваете IFoo.
- Они управляют продолжительностью жизни компонентов. Вы каждый раз хотите, чтобы каждый экземпляр Foo каждый раз, но в других случаях вам может понадобиться один и тот же экземпляр. Вы можете даже хотеть новые экземпляры Foo каждый раз, но введенная панель должна оставаться тем же самым экземпляром.
Как только вы начнете ручное управление композицией и сроками жизни, вы должны начать оценивать услуги, предоставляемые контейнером DI:)
Многие контейнеры DI могут делать гораздо больше, чем выше, но это основные сервисы. Большинство контейнеров предлагают опции для настройки через код или XML.
Когда дело доходит до правильного использования контейнеров, Krzysztof Kozmic только что опубликовал хороший обзор.
Ответ 2
"Это не что иное, как причудливый хеш таблица объектов.
В то время как вышеизложенное является массовым преуменьшением, что легкий способ думать о них. Учитывая коллекцию, если вы запрашиваете один и тот же экземпляр класса - контейнер DI будет решать, предоставлять ли вам кешированную версию или новую или так далее.
Их использование упрощает и упрощает процесс подключения к зависимостям. Представьте, что у вас есть следующие псевдо-классы.
class House(Kitchen, Bedroom)
// Use kitchen and bedroom.
end
class Kitchen()
// Code...
end
class Bedroom()
// Code...
end
Построение дома - это боль без контейнера DI, вам нужно будет создать экземпляр спальни, а затем экземпляр кухни. Если у этих объектов тоже есть зависимости, вам нужно их подключить. В свою очередь, вы можете потратить много строк кода, просто проводя объекты. Только тогда вы могли бы создать действительный дом. Используя контейнер DI/IOC (Inversion of Control), вы говорите, что хотите домашний объект, контейнер DI будет рекурсивно создавать каждую из своих зависимостей и возвращать вам дом.
Без контейнера DI/IOC:
house = new House(new Kitchen(), new Bedroom());
С контейнером DI/IOC:
house = // some method of getting the house
В конце дня они легко кодируют код, легче записывают и переносят ответственность за подключение объектов вместе от проблемы.
Ответ 3
Вы настраиваете контейнер DI, чтобы он знал о ваших интерфейсах и типах - как каждый интерфейс сопоставляется с типом.
Когда вы вызываете Resolve
на нем, он смотрит на отображение и возвращает запрошенный сопоставленный объект.
Некоторые контейнеры DI используют соглашения по конфигурации, например, если вы определяете интерфейс ISomething
, он будет искать конкретный тип Something
для создания и возврата.