Что такое инверсия управления, и когда я должен ее использовать?


65

Я проектирую новую систему и хочу знать, что такое инверсия управления (IOC) и, что более важно, когда ее использовать.

Это должно быть реализовано с помощью интерфейсов или может быть сделано с помощью классов?


Ответы:


62

IoC (см. « Инверсия управления» в Википедии) применяется в тех случаях, когда компонент не может выполнить задачу полностью, поскольку у него нет необходимой информации или функций.

Простейшим примером шаблона IoC были бы функции обратного вызова в C. Например, вы можете объявить функцию:

void Iterator(void *list, Func* f)

Это повторяет listприменение fфункции к каждому элементу. IteratorФункция не знает , как будет обрабатываться каждый элемент, вы просто указать функцию в качестве аргумента, и он обрабатывает их.

Как показывает предыдущий пример, IoC позволяет вам разделить вашу программу на отдельные компоненты, которые не знают друг о друге. Одной из наиболее распространенных версий IoC является Dependecy Injection .

В Dependency Injection каждый компонент должен объявить список зависимостей, необходимых для выполнения его задачи. Во время выполнения специальный компонент (обычно), называемый контейнером IoC, выполняет связывание между этими компонентами. Он пытается предоставить значения для опубликованных зависимостей компонентов.

Вот пример в псевдокоде:

class Foo 
{ 
   <Require Boo>Constructor(Boo boo){ boo.DoSomething } 
}

В этом примере класс Fooимеет конструктор, который требует аргумент типа Booдля выполнения какого-либо действия.

Вы можете создать экземпляр класса, Fooиспользуя код, подобный следующему:

MyContainer.Create(typeof Foo)

MyContainer- это контейнер IoC , который заботится о получении экземпляра Booи передаче его Fooконструктору.

Таким образом, IoC позволяет разделить вашу программу на отдельные части. Это хорошо, потому что:

  • Компоненты могут быть легко протестированы независимо.
  • Сложность программы может быть уменьшена.
  • Вы можете переключать компоненты в другую реализацию.

Однако в некоторых случаях IoC может усложнить понимание кода.

Если вы хотите увидеть хороший пример реального использования IoC , взгляните на Mircosoft Composite UI Application Block и CompositeWPF.

Я надеюсь, что мое объяснение поможет вам.

С уважением,
аку


1
Пять лет спустя, но все же ... Это было отличное описание. Благодарю.
Ник Ходжес

4
О IoC не так уж и много говорится о том, что код становится труднее читать. Читаемость является приоритетом номер один, если вы хотите написать отличное программное обеспечение. Это даже бьет Тестируемость. Вы можете отделить код далеко за пределы его полезности.
Арне Эвертссон

Итак, код, который использует решение на основе интерфейса для всех своих зависимостей, также основан на дизайне IoC?
Никель

18

Поскольку я сам недавно в этом разбирался и сохранил все закладки, я нашел бесценным следующее для изучения IOC / DI.

Оригинальная статья Мартина Фаулерса о МОК / ДИ

Некоторые концепции, чтобы знать в первую очередь

Отличная коллекция учебников IOC / DI

Книга о IOC / DI из Manning Press

Исходный код и объяснение того, как создать свой собственный IOC - причина, по которой чтение исходного кода - это всегда лучший способ понять концепцию.


4

Привет, JMS, в основном IoC / DI позволит вам определить, какую реализацию вы используете один раз, и сохранять статическую копию вашего контейнера для ссылки каждый раз, когда вы захотите ссылаться на нее.

Википедия, вероятно, поможет вам, но я хотел сослаться на вашу вторую часть - да, внедрение классов может быть сделано для классов (т. Е. Каждый раз, когда этот тип класса должен быть передан методу, используйте этот класс), но лучше используйте интерфейсы, потому что таким образом вы можете изменить, какую версию провайдера, репозитория и т. д. вы используете, просто сославшись на нее в своей настройке.

IE, скажем, у вас был интерфейс для чтения потока, и у вас были XMLStreamReader и реализация SQLStreamReader. Затем вы можете передать ссылку на интерфейс вашим методам, а затем в вашем контейнере IoC сообщить, какой из них использовать.

Таким образом, у вас может быть публичный List ReadPeople (читатель IStreamReader), и в настройках вашего контейнера IoC сообщайте ему всякий раз, когда вы ожидаете, что IStreamReader использует SQLStreamReader.

Затем, если вы передумаете позже, вам нужно будет изменить его только в одном месте (настройка вашего контейнера), и не будет иметь значения, сколько методов запрашивает IStreamReader, он всегда получит значение по умолчанию, которое вы указали своему контейнеру подавать.


3

Допустим, у вас есть валидатор для проверки, является ли бизнес действительным в вашей системе. Ваш "BusinessValidator" может иметь поле типа AddressValidator, которое проверяет адресную часть бизнеса. Если вы хотите протестировать BusinessValidator без выполнения внешнего кода (то есть кода addressValidator), то, если вы использовали какой-то IoC / DI в своей инфраструктуре, вы можете легко «вставить» фиктивный addressValidator вместо него и не беспокоиться о тестировании. код выходит за рамки тестируемого класса.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.