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