Самое простое объяснение того, как контейнер DI работает?

Простыми словами и/или в высокоуровневом псевдокоде, как работает контейнер DI и как он используется?

12
задан 22 June 2010 в 19:15
поделиться

3 ответа

По своей сути DI Container создает объекты на основе отображений между интерфейсами и конкретными типами.

Это позволит вам запросить у контейнера абстрактный тип:

IFoo f = container.Resolve<IFoo>();

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

Само по себе это не впечатляет, но DI-контейнеры делают больше:

  • Они используют Auto-Wiring, что означает, что они могут автоматически определить, что если IFoo отображается на Foo, а IBar - на Bar, но Foo имеет зависимость от IBar, то при запросе IFoo будет создан экземпляр Foo с Bar.
  • Они управляют временем жизни компонентов. Вы можете захотеть каждый раз создавать новый экземпляр Foo, но в других случаях вам может понадобиться один и тот же экземпляр. Вы даже можете хотеть каждый раз новые экземпляры Foo, но инжектируемый Bar должен оставаться тем же экземпляром.

Как только вы начнете пытаться вручную управлять композицией и временем жизни, вы начнете ценить услуги, предоставляемые DI-контейнером :)

Многие DI-контейнеры могут делать гораздо больше, чем описано выше, но это основные услуги. Большинство контейнеров предлагают возможности конфигурирования с помощью кода или XML.

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

5
ответ дан 2 December 2019 в 22:04
поделиться

Вы настраиваете контейнер DI так, чтобы он знал о ваших интерфейсах и типах - как каждый интерфейс отображается на тип.

Когда вы вызываете для него Resolve , он просматривает сопоставление и возвращает запрошенный сопоставленный объект.

Некоторые контейнеры DI используют соглашения по конфигурации, например, если вы определяете интерфейс ISomething , он будет искать конкретный тип Something для создания экземпляра и возврата.

2
ответ дан 2 December 2019 в 22:04
поделиться

"Это не что иное, как причудливая хэш таблица объектов. "

Хотя вышесказанное является сильным преуменьшением, это простой способ думать о них. Учитывая коллекцию, если вы запрашиваете один и тот же экземпляр класса - контейнер 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

В конце концов, они делают код проще для понимания, проще для написания и перекладывают ответственность за соединение объектов вместе от текущей проблемы.

4
ответ дан 2 December 2019 в 22:04
поделиться