Что такое инверсия контроля?

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

  1. Что это?
  2. Какую проблему это решает?
  3. Когда это целесообразно использовать, а когда нет?

41 ответ

Решение

Шаблоны Inversion of Control (IoC) и Dependency Injection (DI) предназначены для удаления зависимостей из вашего кода.

Например, допустим, что в вашем приложении есть компонент текстового редактора, и вы хотите обеспечить проверку орфографии. Ваш стандартный код будет выглядеть примерно так:

public class TextEditor {

    private SpellChecker checker;

    public TextEditor() {
        this.checker = new SpellChecker();
    }
}

То, что мы сделали здесь, создает зависимость между TextEditor и SpellChecker, В сценарии IoC мы бы вместо этого сделали что-то вроде этого:

public class TextEditor {

    private IocSpellChecker checker;

    public TextEditor(IocSpellChecker checker) {
        this.checker = checker;
    }
}

В первом примере кода мы создаем SpellChecker (this.checker = new SpellChecker();), что означает TextEditor класс напрямую зависит от SpellChecker учебный класс.

Во втором примере кода мы создаем абстракцию, имея SpellChecker класс зависимости в TextEditor подпись конструктора (без инициализации зависимости в классе). Это позволяет нам вызвать зависимость и затем передать ее в класс TextEditor следующим образом:

SpellChecker sc = new SpellChecker; // dependency
TextEditor textEditor = new TextEditor(sc);

Теперь клиент создает TextEditor класс имеет контроль над тем, SpellChecker реализация использовать, потому что мы вводим зависимость к TextEditor подпись.

Это простой пример, есть хорошая серия статей Симоне Бусоли, которая объясняет это более подробно.

Инверсия управления - это то, что вы получаете, когда ваши программы вызывают, например, программу с графическим интерфейсом.

Например, в меню старой школы вы могли бы иметь:

print "enter your name"
read name
print "enter your address"
read address
etc...
store in database

тем самым контролируя поток взаимодействия с пользователем.

В программе с графическим интерфейсом или что-то подобное мы говорим:

when the user types in field a, store it in NAME
when the user types in field b, store it in ADDRESS
when the user clicks the save button, call StoreInDatabase

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

По сути, все, что имеет цикл обработки событий, обратные вызовы или триггеры выполнения, попадает в эту категорию.

Что такое инверсия контроля?

Если вы выполните эти два простых шага, вы сделали инверсию управления:

  1. Отделяйте часть " что делать" от части " когда делать".
  2. Убедитесь, что когда часть знает как можно меньше о какой части; и наоборот.

Для каждого из этих шагов возможно несколько методов, основанных на технологии / языке, которые вы используете для своей реализации.

-

Инверсионная часть Inversion of Control (IoC) - запутанная вещь; потому что инверсия это относительный термин. Лучший способ понять IoC - забыть об этом слове!

-

Примеры

  • Обработка событий. Обработчики событий (часть с заданиями) - Создание событий (часть с заданиями)
  • Интерфейсы. Компонентный клиент (часть при выполнении) - реализация интерфейса компонента (часть, что нужно сделать)
  • xUnit fixure. Setup и TearDown (часть "что делать") - платформы xUnit вызывают программу установки в начале и TearDown в конце (часть "когда нужно делать")
  • Шаблон метода проектирования шаблона. часть шаблона метода when-to-do - примитивная реализация подкласса what-to-do
  • Методы контейнера DLL в COM. DllMain, DllCanUnload и т. Д. (Часть "что делать") - COM/OS (часть "когда делать")

Инверсия Контроля - это разделение проблем.

Без IoC: у вас есть портативный компьютер, и вы случайно разбиваете экран. И, черт возьми, вы найдете такую ​​же модель экрана ноутбука нигде на рынке. Итак, вы застряли.

С IoC: у вас есть настольный компьютер, и вы случайно разбиваете экран. Вы обнаружите, что можете просто взять практически любой настольный монитор с рынка, и он хорошо работает с вашим рабочим столом.

В этом случае ваш рабочий стол успешно реализует IoC. Он принимает различные типы мониторов, в то время как ноутбук этого не делает, для его исправления требуется определенный экран.

Инверсия Контроля (или IoC) - это получение свободы (Вы женаты, вы потеряли свободу и вас контролируют. Вы развелись, вы только что внедрили Инверсию Контроля. Это то, что мы называли "разъединенными". Хорошая компьютерная система). препятствует некоторым очень близким отношениям.) больше гибкости (кухня в вашем офисе подает только чистую водопроводную воду, это ваш единственный выбор, когда вы хотите пить. Ваш начальник внедрил Inversion of Control, установив новую кофемашину. Теперь вы получаете гибкость выбора водопроводной воды или кофе.) и меньшая зависимость (у вашего партнера есть работа, у вас нет работы, вы финансово зависите от своего партнера, поэтому вы находитесь под контролем. Вы нашли работу, вы внедрили Inversion of Контроль. Хорошая компьютерная система поощряет независимость.)

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

Внедряя Inversion of Control, потребитель программного / объектного объекта получает больше элементов управления / опций над программным обеспечением / объектами вместо того, чтобы управлять им или иметь меньше опций.

С учетом вышеизложенных идей. Мы все еще скучаем по ключевой части IoC. В сценарии IoC потребитель программного обеспечения / объектов представляет собой сложную структуру. Это означает, что созданный вами код не вызывается вами. Теперь давайте объясним, почему этот способ работает лучше для веб-приложения.

Предположим, ваш код представляет собой группу работников. Им нужно построить машину. Этим работникам нужно место и инструменты (программная структура) для сборки автомобиля. Традиционный программный фреймворк будет похож на гараж со множеством инструментов. Поэтому рабочие должны сами составить план и использовать инструменты для сборки автомобиля. Создание автомобиля - дело непростое, рабочим будет очень сложно правильно планировать и сотрудничать. Современная структура программного обеспечения будет похожа на современный автомобильный завод со всеми необходимыми средствами и менеджерами. Рабочие не должны составлять никакого плана, менеджеры (часть структуры, они самые умные люди и разработали самый сложный план) помогут координировать, чтобы работники знали, когда выполнять свою работу (структура называет ваш код). Рабочие просто должны быть достаточно гибкими, чтобы использовать любые инструменты, которые им дают менеджеры (используя Dependency Injection).

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

Современные веб-приложения с архитектурой MVC зависят от среды, в которой выполняется маршрутизация URL, и устанавливают контроллеры для вызова платформы.

Инъекция зависимостей и инверсия управления взаимосвязаны. Инъекция зависимости находится на микроуровне, а инверсия управления - на макроуровне. Вы должны съесть каждый кусочек (внедрить DI), чтобы закончить прием пищи (внедрить IoC).

Перед использованием Inversion of Control вы должны хорошо знать, что у него есть свои плюсы и минусы, и вы должны знать, почему вы используете его, если вы это делаете.

Плюсы:

  • Ваш код отделен, так что вы можете легко обмениваться реализациями интерфейса с альтернативными реализациями
  • Это сильный мотиватор для кодирования против интерфейсов вместо реализаций
  • Очень легко написать модульные тесты для вашего кода, потому что он не зависит ни от чего, кроме объектов, которые он принимает в своем конструкторе / установщике, и вы можете легко инициализировать их с нужными объектами в изоляции.

Минусы:

  • IoC не только инвертирует поток управления в вашей программе, но и значительно затуманивает его. Это означает, что вы больше не можете просто читать свой код и переходить из одного места в другое, потому что соединения, которые обычно были бы в вашем коде, больше не находятся в коде. Вместо этого именно в XML-файлах конфигурации или аннотациях и в коде вашего контейнера IoC интерпретируются эти метаданные.
  • Возникает новый класс ошибок, в которых вы неправильно настраиваете XML-конфигурацию или свои аннотации, и вы можете потратить много времени на выяснение того, почему ваш контейнер IoC вводит нулевую ссылку в один из ваших объектов при определенных условиях.

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

  1. Статья в Википедии. Для меня инверсия контроля превращает ваш последовательно написанный код и превращает его в структуру делегирования. Вместо того, чтобы ваша программа явно контролировала все, ваша программа устанавливает класс или библиотеку с определенными функциями, которые будут вызываться, когда происходят определенные вещи.

  2. Это решает дублирование кода. Например, в старые времена вы вручную писали свой собственный цикл событий, опрашивая системные библиотеки на предмет новых событий. В настоящее время большинство современных API-интерфейсов просто сообщают системным библиотекам, какие события вас интересуют, и они сообщают вам, когда они происходят.

  3. Инверсия управления - это практичный способ уменьшить дублирование кода, и если вы обнаружите, что копируете весь метод и изменяете только небольшой фрагмент кода, вы можете рассмотреть его с инверсией управления. Инверсия управления упрощается во многих языках благодаря концепции делегатов, интерфейсов или даже необработанных указателей на функции.

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

Отвечая только на первую часть. Что это?

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

Предположим, вы объект. И вы идете в ресторан

Без IoC: вы просите "яблоко", и вам всегда подают яблоко, когда вы спрашиваете больше.

С IoC: Вы можете попросить "фрукты". Вы можете получать разные фрукты каждый раз, когда вас обслуживают. например, яблоко, апельсин или арбуз.

Итак, очевидно, что IoC предпочтительнее, когда вам нравятся сорта.

Но я думаю, что вы должны быть очень осторожны с этим. Если вы будете злоупотреблять этим шаблоном, вы создадите очень сложный дизайн и еще более сложный код.

Как в этом примере с TextEditor: если у вас есть только один SpellChecker, может быть, нет необходимости использовать IoC? Если вам не нужно писать модульные тесты или что-то...

В любом случае: будь разумным. Шаблон дизайна - это хорошая практика, но не Библия, которую нужно проповедовать. Не вставляйте это везде.

IoC / DI для меня выталкивает зависимости к вызывающим объектам. Супер просто.

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

  1. Инверсия управления - это шаблон, используемый для разделения компонентов и слоев в системе. Шаблон реализуется путем внедрения зависимостей в компонент при его создании. Эти зависимости обычно предоставляются в качестве интерфейсов для дальнейшей развязки и поддержки тестируемости. Контейнеры IoC / DI, такие как Castle Windsor, Unity - это инструменты (библиотеки), которые можно использовать для обеспечения IoC. Эти инструменты предоставляют расширенные функции помимо простого управления зависимостями, включая время жизни, AOP / перехват, политику и т. Д.

  2. а. Освобождает компонент от ответственности за управление его зависимостями.
    б. Предоставляет возможность менять реализации зависимостей в разных средах.
    с. Позволяет компоненту быть проверенным путем проверки зависимостей.
    д. Предоставляет механизм для совместного использования ресурсов в приложении.

  3. а. Критически важен при разработке на основе тестов. Без IoC тестирование может быть затруднено, поскольку тестируемые компоненты тесно связаны с остальной частью системы.
    б. Критически важен при разработке модульных систем. Модульная система - это система, компоненты которой могут быть заменены без перекомпиляции.
    с. Критически, если есть много сквозных проблем, которые необходимо решить, в частности, в корпоративном приложении.

Позвольте сказать, что мы делаем какую-то встречу в каком-то отеле.

Много людей, много графинов с водой, много пластиковых стаканчиков.

Когда кто-то хочет пить, она наполняет чашку, пьет и бросает чашку на пол.

Через час или около того у нас пол покрыт пластиковыми стаканчиками и водой.

Пусть инвертирует контроль.

Та же встреча в том же месте, но вместо пластиковых стаканчиков у нас есть официант с одной стеклянной чашкой (синглтон)

и она все время предлагает гостям выпить.

Когда кто-то хочет выпить, она достает из официанта стакан, пьет и возвращает его обратно официанту.

Оставляя в стороне вопрос о гигиеничности, последняя форма контроля питьевого процесса гораздо более эффективна и экономична.

И это именно то, что делает Spring (другой контейнер IoC, например: Guice). Вместо того, чтобы позволить приложению создавать то, что ему нужно, используя новое ключевое слово (с пластиковой чашкой), контейнер Spring IoC все время предлагает приложению один и тот же экземпляр (singleton) нужного объекта (стакан воды).

Думайте о себе как об организаторе такой встречи. Вам нужен способ сообщить администрации отеля, что

участникам собрания понадобится стакан воды, но не кусок пирога.

Пример:-

public class MeetingMember {

    private GlassOfWater glassOfWater;

    ...

    public void setGlassOfWater(GlassOfWater glassOfWater){
        this.glassOfWater = glassOfWater;
    }
    //your glassOfWater object initialized and ready to use...
    //spring IoC  called setGlassOfWater method itself in order to
    //offer to meetingMember glassOfWater instance

}

Полезные ссылки:-

Я напишу мое простое понимание этих двух терминов:

For quick understanding just read examples*

Инъекция зависимости (DI):
Внедрение зависимостей обычно означает передачу объекта, от которого зависит метод, в качестве параметра метода, а не создание метода зависимым объектом.
На практике это означает, что метод не зависит напрямую от конкретной реализации; любая реализация, которая соответствует требованиям, может быть передана в качестве параметра.

С этим объекты сообщают свои зависимости. И весна делает это доступным.
Это приводит к слабосвязанной разработке приложений.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,
              IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT
   (if address is defines as dependency by Employee object)

Контейнер инверсии контроля (IoC):
Это общая характеристика фреймворков, МОК управляет объектами Java
- от создания экземпляров до уничтожения через BeanFactory.
-Java-компоненты, которые создаются контейнером IoC, называются bean-компонентами, а контейнер IoC управляет областью действия bean-компонента, событиями жизненного цикла и любыми функциями AOP, для которых он был настроен и закодирован.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it,

Внедряя Inversion of Control, потребитель программного / объектного объекта получает больше элементов управления / опций над программным обеспечением / объектами вместо того, чтобы управлять им или иметь меньше опций.

Инверсия управления в качестве руководства по проектированию служит следующим целям:

Происходит разделение выполнения определенной задачи от реализации.
Каждый модуль может сосредоточиться на том, для чего он предназначен.
Модули не делают никаких предположений о том, что делают другие системы, но полагаются на свои контракты.
Замена модулей не оказывает побочного влияния на другие модули
Я буду держать вещи абстрактными здесь. Вы можете посетить следующие ссылки для подробного понимания темы.
Хорошее чтиво с примером

Детальное объяснение

Я нашел очень четкий пример, который объясняет, как "инвертируется управление".

Классический код (без внедрения зависимости)

Вот как примерно будет работать код, не использующий DI:

  • Приложению требуется Foo (например, контроллер), поэтому:
  • Приложение создает Foo
  • Приложение вызывает Foo
    • Foo нуждается в Bar (например, услуга), поэтому:
    • Фу создает бар
    • Фу называет бар
      • Бар нужен Bim (сервис, хранилище, …), поэтому:
      • Бар создает Бим
      • Бар что-то делает

Использование внедрения зависимости

Вот как примерно будет работать код, использующий DI:

  • Приложению нужен Foo, которому нужен Bar, которому нужен Bim, поэтому:
  • Приложение создает Bim
  • Приложение создает бар и дает ему Бим
  • Приложение создает Foo и дает ему Bar
  • Приложение вызывает Foo
    • Фу называет бар
      • Бар что-то делает

Управление зависимостями инвертируется от одного вызываемого к одному вызывающему.

Какие проблемы это решает?

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

Пример: предположим, что ваше приложение хранит загруженный пользователем файл на Google Диске, с DI код вашего контроллера может выглядеть так:

class SomeController
{
    private $storage;

    function __construct(StorageServiceInterface $storage)
    {
        $this->storage = $storage;
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

class GoogleDriveService implements StorageServiceInterface
{
    public function authenticate($user) {}
    public function putFile($file) {}
    public function getFile($file) {}
}

Когда ваши требования изменятся, скажем, вместо Google Drive вас попросят использовать Dropbox. Вам нужно только написать реализацию Dropbox для StorageServiceInterface. Вам не нужно вносить никаких изменений в контроллер, пока реализация Dropbox придерживается StorageServiceInterface.

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

Вместо этого, если у вас был класс контроллера для создания объекта хранения с new ключевое слово как это:

class SomeController
{
    private $storage;

    function __construct()
    {
        $this->storage = new GoogleDriveService();
    }

    public function myFunction () 
    {
        return $this->storage->getFile($fileName);
    }
}

Если вы хотите изменить с помощью реализации Dropbox, вы должны заменить все строки, где new Объект GoogleDriveService создается и использует DropboxService. Кроме того, при тестировании класса SomeController конструктор всегда ожидает класс GoogleDriveService и срабатывают фактические методы этого класса.

Когда это уместно, а когда нет? По моему мнению, вы используете DI, когда думаете, что есть (или могут быть) альтернативные реализации класса.

Я согласен с NilObject, но я хотел бы добавить к этому:

если вы обнаружите, что копируете целый метод и изменяете только небольшой фрагмент кода, вы можете рассмотреть его с инверсией управления

Если вы обнаружите, что копируете и вставляете код, вы почти всегда делаете что-то не так. Зашифрован как принцип дизайна Один раз и только один раз.

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

В терминах программирования она передала функцию обратного вызова getProductList() к функции, которую вы выполняете doShopping();

Это позволяет пользователю функции определять некоторые ее части, делая ее более гибкой.

Например, задача № 1 - создать объект. Без концепции IOC задача № 1 должна выполняться программистом. Но с концепцией IOC задача № 1 будет выполняться контейнером.

Короче говоря, управление переворачивается из программатора в контейнер. Итак, это называется инверсией контроля.

Я нашел один хороший пример здесь.

Кажется, что самая запутанная вещь в "IoC" - это аббревиатура и название, за которым оно стоит, - это слишком гламурное имя - почти шумное имя.

Нужно ли нам имя, чтобы описать разницу между процедурным и управляемым событиями программированием? Хорошо, если нам нужно, но нужно ли нам выбирать новое имя "больше, чем жизнь", которое смущает больше, чем решает?

Я понимаю, что ответ уже был дан здесь. Но я все еще думаю, что некоторые основы инверсии управления должны быть подробно обсуждены здесь для будущих читателей.

Инверсия контроля (IoC) была построена по очень простому принципу, который называется принцип Голливуда. И это говорит о том, что

Не звоните нам, мы вам позвоним

Это означает, что не отправляйтесь в Голливуд, чтобы осуществить свою мечту, а если вы достойны, тогда Голливуд найдет вас и осуществит вашу мечту. В значительной степени перевернутый, а?

Теперь, когда мы обсуждаем принцип IoC, мы забываем о Голливуде. Для IoC должно быть три элемента: Голливуд, ты и задача, подобная осуществлению твоей мечты.

В нашем мире программирования Голливуд представляет собой общую структуру (может быть написана вами или кем-то еще), вы представляете написанный вами код пользователя, а задача представляет собой то, что вы хотите выполнить с помощью своего кода. Теперь вы никогда не запускаете свою задачу самостоятельно, а не в IoC! Скорее вы спроектировали все так, чтобы ваша структура вызывала вашу задачу для вас. Таким образом, вы создали многоразовую структуру, которая может сделать кого-то героем или другого злодеем. Но эта структура всегда отвечает, она знает, когда кого-то выбирать, а кто-то знает, кем она хочет быть.

Пример из реальной жизни будет дан здесь. Предположим, вы хотите разработать веб-приложение. Итак, вы создаете структуру, которая будет обрабатывать все обычные вещи, которые должно обрабатывать веб-приложение, такие как обработка http-запроса, создание меню приложения, обслуживание страниц, управление файлами cookie, запуск событий и т. Д.

А затем вы оставляете несколько хуков в своей инфраструктуре, где вы можете поместить дополнительные коды для создания пользовательского меню, страниц, файлов cookie, регистрации некоторых пользовательских событий и т. Д. При каждом запросе браузера ваша платформа будет запускаться и выполнять ваши пользовательские коды, если они будут подключены, а затем вернуть их обратно. в браузер.

Итак, идея довольно проста. Вместо того, чтобы создавать пользовательское приложение, которое будет контролировать все, сначала вы создаете многократно используемую среду, которая будет контролировать все, затем пишете свои пользовательские коды и подключаете их к среде, чтобы выполнить их вовремя.

Laravel и EJB являются примерами таких рамок.

Ссылка:

https://martinfowler.com/bliki/InversionOfControl.html

https://en.wikipedia.org/wiki/Inversion_of_control

Инверсия управления - это общий принцип, в то время как Dependency Injection реализует этот принцип как шаблон проектирования для построения графа объекта (т.е. конфигурация контролирует, как объекты ссылаются друг на друга, а не сам объект, контролирующий, как получить ссылку на другой объект).

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

Для тех, кто заинтересован в более глубоком рассмотрении Inversion of Control, была опубликована статья с изложением более полной картины Inversion of Control как шаблона проектирования (OfficeFloor: использование шаблонов office для улучшения проектирования программного обеспечения http://doi.acm.org/10.1145/2739011.2739013 с бесплатной копией, доступной для загрузки по http://www.officefloor.net/mission.html)

То, что идентифицировано, является следующим отношением:

Инверсия управления (для методов) = впрыск зависимости (состояния) + впрыск продолжения + впрыск резьбы

Мне нравится это объяснение: http://joelabrahamsson.com/inversion-of-control-an-introduction-with-examples-in-net/

Все начинается просто и показывает примеры кода.

Потребителю X нужен потребляемый класс Y, чтобы чего-то достичь. Это все хорошо и естественно, но действительно ли X нужно знать, что он использует Y?

Разве не достаточно того, что X знает, что использует то, что имеет поведение, методы, свойства и т. Д. Y, не зная, кто на самом деле реализует это поведение?

Извлекая абстрактное определение поведения, используемого X в Y, проиллюстрированного как I ниже, и позволяя потребителю X использовать экземпляр этого вместо Y, он может продолжать делать то, что он делает, не зная специфики о Y.

На иллюстрации выше Y реализует I, а X использует экземпляр I. Хотя вполне возможно, что X по-прежнему использует Y, интересно то, что X этого не знает. Он просто знает, что использует то, что реализует I.

Прочитайте статью для получения дополнительной информации и описания преимуществ, таких как:

  • X больше не зависит от Y
  • Более гибкая реализация может быть решена во время выполнения
  • Выделение блока кода, упрощение тестирования

...

IoC - это инверсия отношений между вашим кодом и сторонним кодом (библиотека / фреймворк):

  • При обычной разработке программного обеспечения вы пишете метод main () и вызываете "библиотечные" методы. Вы контролируете:)
  • В IoC "framework" управляет main () и вызывает ваши методы. Каркас находится под контролем:(

DI (Dependency Injection) рассказывает о том, как управление передается в приложение. Традиционное настольное приложение имело поток управления от вашего приложения (метод main ()) к вызовам других библиотечных методов, но с потоком управления DI инвертировалось, что фреймворк заботится о запуске вашего приложения, его инициализации и вызове ваших методов при необходимости.

В итоге ты всегда побеждаешь:)

Очень простое письменное объяснение можно найти здесь

http://binstock.blogspot.in/2008/01/excellent-explanation-of-dependency.html

это говорит

"Любое нетривиальное приложение состоит из двух или более классов, которые взаимодействуют друг с другом для выполнения некоторой бизнес-логики. Традиционно каждый объект отвечает за получение своих собственных ссылок на объекты, с которыми он взаимодействует (его зависимости). При применении DI объекты получают свои зависимости во время создания некоторой внешней сущностью, которая координирует каждый объект в системе. Другими словами, зависимости вводятся в объекты ".

Поскольку на этот вопрос уже есть много ответов, но ни один из них не показывает разбивку термина "Управление инверсией", я вижу возможность дать более краткий и полезный ответ.

Инверсия управления - это шаблон, реализующий принцип инверсии зависимостей (DIP). DIP утверждает следующее: 1. Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций (например, интерфейсов). 2. Абстракции не должны зависеть от деталей. Детали (конкретные реализации) должны зависеть от абстракций.

Есть три типа инверсии управления:

Провайдеры инверсии интерфейса не должны определять интерфейс. Вместо этого потребитель должен определить интерфейс, а поставщики должны его реализовать. Инверсия интерфейса позволяет избавиться от необходимости изменять потребителя каждый раз при добавлении нового провайдера.

Инверсия потока Изменяет управление потоком. Например, у вас есть консольное приложение, в котором вы просили ввести много параметров, и после каждого введенного параметра вы вынуждены нажимать Enter. Вы можете применить здесь Flow Inversion и реализовать настольное приложение, в котором пользователь может выбрать последовательность ввода параметров, пользователь может редактировать параметры, и на последнем шаге пользователю нужно нажать Enter только один раз.

Инверсия создания Это может быть реализовано с помощью следующих шаблонов: заводской шаблон, локатор службы и внедрение зависимостей. Creation Inversion помогает устранить зависимости между типами, перемещая процесс создания объектов зависимости за пределы типа, который использует эти объекты зависимости. Почему зависимости плохие? Вот пара примеров: прямое создание нового объекта в вашем коде усложняет тестирование; невозможно изменять ссылки в сборках без перекомпиляции (нарушение принципа OCP); вы не можете легко заменить пользовательский интерфейс рабочего стола веб-интерфейсом.

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

Программирование говорения

IoC в простых терминах: это использование интерфейса в качестве способа задания чего-либо (такого как поле или параметр) в качестве подстановочного знака, который может использоваться некоторыми классами. Это позволяет повторно использовать код.

Например, предположим, что у нас есть два класса: Dog и Cat. Оба имеют одинаковые качества / состояния: возраст, размер, вес. Таким образом, вместо создания класса обслуживания под названием DogService и CatService, я могу создать один, называемый AnimalService, который позволяет использовать Dog и Cat только в том случае, если они используют интерфейс IAnimal.

Однако, прагматично говоря, он имеет некоторые недостатки.

а) Большинство разработчиков не знают, как его использовать. Например, я могу создать класс с именем Customer и автоматически (с помощью инструментов IDE) создать интерфейс под названием ICustomer. Таким образом, не редко можно найти папку, заполненную классами и интерфейсами, независимо от того, будут ли интерфейсы использоваться повторно или нет. Это называется BLOATED. Некоторые люди могут утверждать, что "возможно, в будущем мы могли бы использовать это".:-|

б) имеет некоторые ограничения. Например, давайте поговорим о случае с Dog и Cat, и я хочу добавить новый сервис (функциональность) только для собак. Допустим, я хочу посчитать, сколько дней мне нужно дрессировать собаку (trainDays()), для кошки это бесполезно, кошек нельзя дрессировать (я шучу).

б.1) Если я добавлю trainDays() в сервис AnimalService, то он также работает с кошками и вообще не действует.

б.2) я могу добавить условие в trainDays() где он оценивает, какой класс используется. Но это полностью сломает IoC.

б.3) Я могу создать новый класс сервиса под названием DogService только для новой функциональности. Но это повысит удобство сопровождения кода, потому что у нас будет два класса обслуживания (со схожей функциональностью) для Dog, и это плохо.

Я прочитал много ответов по этому поводу, но если кто-то все еще сбит с толку и нуждается в дополнительном "термине непрофессионала", чтобы объяснить IoC, вот мое мнение:

Представьте, что родитель и ребенок разговаривают друг с другом.

Без IoC:

* Родитель: Вы можете говорить, только когда я задаю вам вопросы, и вы можете действовать, только когда я даю вам разрешение.

Родитель: Это означает, что вы не можете спросить меня, можете ли вы поесть, поиграть, сходить в ванную или даже поспать, если я вас не спрошу.

Родитель: Хочешь поесть?

Ребенок: Нет.

Родитель: Хорошо, я вернусь. Подожди меня.

Ребенок: (Хочет поиграть, но, поскольку родители не спрашивают, ребенок ничего не может делать).

После 1 часа...

Родитель: Я вернулся. Ты хочешь поиграть?

Ребенок: Да.

Родитель: разрешение предоставлено.

Ребенок: (наконец-то умеет играть).

Этот простой сценарий объясняет, что элемент управления центрирован по родительскому элементу. Свобода ребенка ограничена и сильно зависит от вопроса родителей. Ребенок может говорить ТОЛЬКО, когда его просят говорить, и может действовать ТОЛЬКО с разрешения.

С IoC:

Теперь у ребенка есть возможность задавать вопросы, а родитель может отвечать ответами и разрешениями. Просто означает, что управление перевернуто! Теперь ребенок может задавать вопросы в любое время, и, хотя все еще существует зависимость с родителем в отношении разрешений, он не зависит в способах говорить / задавать вопросы.

С технологической точки зрения это очень похоже на взаимодействие консоли / оболочки / cmd с графическим интерфейсом. (Это ответ Марка Харрисона выше второго верхнего ответа). В консоли вы зависите от того, что вам задают / отображают, и вы не можете переходить к другим меню и функциям, не ответив сначала на этот вопрос; следуя строгой последовательной схеме. (программно это похоже на цикл метода / функции). Однако с графическим интерфейсом пользователя меню и функции представлены, и пользователь может выбрать все, что ему нужно, что дает больше контроля и меньше ограничений. (программно меню имеет обратный вызов при выборе и выполняется действие).

Создание объекта в классе называется тесной связью, Spring удаляет эту зависимость, следуя шаблону проектирования (DI/IOC). В котором объект класса передается в конструкторе, а не в классе. Более того, мы даем ссылочную переменную суперкласса в конструкторе, чтобы определить более общую структуру.

Я чувствую себя немного неловко, отвечая на этот вопрос с таким количеством предыдущих ответов, но я просто не думал, что какой-либо из ответов просто изложил концепцию достаточно просто.

Итак, поехали...

В приложении, отличном от IOC, вы должны закодировать поток процесса и включить в него все подробные шаги. Рассмотрим программу, которая создает отчет — она будет включать в себя код для установки подключения к принтеру, печати заголовка, затем итерации по подробным записям, затем печати нижнего колонтитула, возможно, для выполнения перевода страницы и т. д.

В версии программы отчета IOC вы должны настроить экземпляр универсального повторно используемого класса Report, то есть класса, который содержит поток процесса для печати отчета, но не содержит в себе никаких деталей. Конфигурация, которую вы предоставляете, может использовать DI, чтобы указать, какой класс отчет должен вызывать для печати заголовка, какой класс отчет должен вызывать для печати строки сведений и какой класс отчет должен вызывать для печати нижнего колонтитула.

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

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

В некотором смысле IOC можно сравнить с приложением для резервного копирования диска — резервное копирование всегда выполняет одни и те же шаги, но набор резервируемых файлов может быть совершенно другим.

А теперь, чтобы конкретно ответить на исходные вопросы...

  • Что это такое? IOC полагается на повторно используемый класс контроллера и предоставляет детали, специфичные для вашей проблемы.
  • Какую проблему он решает? Предотвращает необходимость повторного определения управляющего потока процесса.
  • Когда уместно использовать, а когда нет? Всякий раз, когда вы создаете поток процессов, поток управления всегда один и тот же, а меняются только детали. Вы не будете использовать его при создании одноразового пользовательского потока процессов.

Наконец, IOC — это не DI, а DI — это не IOC — DI часто может использоваться в IOC (чтобы указать детали абстрактного управляющего класса).

Во всяком случае - я надеюсь, что это поможет.

Другие вопросы по тегам