В программной инженерии инверсия управления ( IoC ) — это принцип проектирования, при котором пользовательские части компьютерной программы получают поток управления из внешнего источника (например, фреймворка ). Термин «инверсия» является историческим: архитектура программного обеспечения с таким дизайном «инвертирует» управление по сравнению с процедурным программированием . В процедурном программировании пользовательский код программы вызывает повторно используемые библиотеки для выполнения общих задач, но при инверсии управления внешний источник или фреймворк вызывает пользовательский код.
Инверсия управления широко используется фреймворками разработки приложений с момента появления сред GUI [1] [2] и продолжает использоваться как в средах GUI, так и в фреймворках приложений веб-серверов . Инверсия управления делает фреймворк расширяемым с помощью методов, определенных программистом приложения. [3]
Программирование, управляемое событиями, часто реализуется с использованием IoC, так что пользовательский код должен заниматься только обработкой событий, в то время как цикл событий и отправка событий/сообщений обрабатываются фреймворком или средой выполнения. В фреймворках приложений веб-сервера отправка обычно называется маршрутизацией, а обработчики могут называться конечными точками.
Фраза «инверсия управления» также стала отдельно использоваться в сообществе программистов Java для обозначения шаблонов внедрения зависимостей (передачи объектам необходимых им сервисов), которые встречаются с «контейнерами IoC» в фреймворках Java, таких как фреймворк Spring . [4] В этом другом смысле «инверсия управления» относится к предоставлению фреймворку контроля над реализациями зависимостей, которые используются объектами приложения [5], а не к изначальному значению предоставления фреймворку контроля потока (контроля над временем выполнения кода приложения, например, обратных вызовов).
Например, при традиционном программировании основная функция приложения может вызывать функции в библиотеке меню, чтобы отобразить список доступных команд и запросить у пользователя выбор одной из них. [6] Таким образом, библиотека вернет выбранную опцию в качестве значения вызова функции, а основная функция использует это значение для выполнения соответствующей команды. Такой стиль был распространен в текстовых интерфейсах . Например, почтовый клиент может отображать экран с командами для загрузки новой почты, ответа на текущую почту, создания новой почты и т. д., и выполнение программы будет блокироваться до тех пор, пока пользователь не нажмет клавишу для выбора команды.
С другой стороны, при инверсии управления программа будет написана с использованием программной среды , которая знает общие поведенческие и графические элементы, такие как системы окон , меню, управление мышью и т. д. Пользовательский код «заполняет пробелы» для среды, например, предоставляет таблицу пунктов меню и регистрирует подпрограмму кода для каждого пункта, но именно среда отслеживает действия пользователя и вызывает подпрограмму при выборе пункта меню. В примере с почтовым клиентом среда может отслеживать как ввод с клавиатуры, так и мыши и вызывать команду, вызванную пользователем любым из этих способов, и в то же время отслеживать сетевой интерфейс , чтобы узнать, поступают ли новые сообщения, и обновлять экран при обнаружении какой-либо сетевой активности. Та же среда может использоваться в качестве скелета для программы электронных таблиц или текстового редактора. И наоборот, среда ничего не знает о веб-браузерах, электронных таблицах или текстовых редакторах; реализация их функциональности требует пользовательского кода.
Инверсия управления несет в себе сильный смысл, что повторно используемый код и проблемно-специфический код разрабатываются независимо, даже если они работают вместе в приложении. Обратные вызовы , планировщики , циклы событий и шаблонный метод являются примерами шаблонов проектирования , которые следуют принципу инверсии управления, хотя этот термин чаще всего используется в контексте объектно-ориентированного программирования . ( Внедрение зависимости является примером отдельной, конкретной идеи «инвертирования управления над реализациями зависимостей», популяризированной фреймворками Java.) [4]
Инверсию контроля иногда называют «принципом Голливуда: не звоните нам, мы сами вам позвоним» [1] .
Инверсия управления — не новый термин в информатике. Мартин Фаулер прослеживает этимологию фразы до 1988 года, [7] но она тесно связана с концепцией инверсии программы, описанной Майклом Джексоном в его методологии структурного программирования Джексона в 1970-х годах. [8] Восходящий парсер можно рассматривать как инверсию нисходящего парсера : в одном случае управление принадлежит парсеру, а в другом — принимающему приложению.
Термин был использован Майклом Мэттссоном в диссертации (в его первоначальном значении фреймворка, вызывающего код приложения, а не наоборот) [9] , а затем был взят оттуда [10] Стефано Маццокки и популяризирован им в 1999 году в несуществующем проекте Apache Software Foundation, Avalon, в котором он относился к родительскому объекту, передающему зависимости дочернего объекта в дополнение к управлению потоком выполнения. [11] Фраза была дополнительно популяризирована в 2004 году Робертом С. Мартином и Мартином Фаулером , последний из которых прослеживает происхождение термина до 1980-х годов. [7]
В традиционном программировании поток бизнес -логики определяется объектами, которые статически связаны друг с другом. При инверсии управления поток зависит от графа объектов, который создается во время выполнения программы. Такой динамический поток становится возможным благодаря взаимодействиям объектов, которые определяются посредством абстракций. Эта привязка во время выполнения достигается такими механизмами, как внедрение зависимостей или локатор служб . В IoC код также может быть связан статически во время компиляции, но поиск кода для выполнения осуществляется путем чтения его описания из внешней конфигурации вместо прямой ссылки в самом коде.
При внедрении зависимости зависимый объект или модуль соединяется с объектом, который ему нужен во время выполнения . Какой именно объект будет удовлетворять зависимости во время выполнения программы, обычно невозможно узнать во время компиляции с помощью статического анализа . Хотя здесь этот принцип описывается в терминах взаимодействия объектов, его можно применять и к другим методологиям программирования, помимо объектно-ориентированного программирования .
Для того чтобы запущенная программа могла связать объекты друг с другом, объекты должны обладать совместимыми интерфейсами . Например, класс A
может делегировать поведение интерфейсу I
, который реализуется классом B
; программа создает экземпляры A
и B
, а затем внедряет B
в A
.
Веб-браузеры реализуют инверсию управления для событий DOM в HTML. Разработчик приложения использует document.addEventListener()
для регистрации обратного вызова.
<!doctype html> < html lang = "en" > < head > < meta charset = "utf-8" > < title > Уровень DOM 2 </ title > </ head > < body > < h1 > Обработчик событий уровня DOM 2 </ h1 > < p >< large >< span id = "output" ></ span ></ large ></ p > <script> var registeredListener = function () { document.getElementById ( "output" ). innerHTML = " <large> Был вызван зарегистрированный прослушиватель.</large> " ; } document.addEventListener ( " click " , registeredListener , true ) ; document . getElementById ( "output" ). innerHTML = "<large>Обработчик событий зарегистрирован. Если вы щелкните страницу, ваш веб-браузер вызовет обработчик событий.</large>" </ скрипт > </ тело > </ html >
Этот пример кода для веб-приложения ASP.NET Core создает хост веб-приложения, регистрирует конечную точку, а затем передает управление фреймворку: [12]
var builder = WebApplication.CreateBuilder ( args ) ; var app = builder.Build ( ) ; app.MapGet ( "/" , ( ) => " Hello World!" ) ; app.Run ( ) ;
Маршрутизация отвечает за сопоставление входящих HTTP-запросов и отправку этих запросов в исполняемые конечные точки приложения. Конечные точки — это единицы исполняемого кода обработки запросов приложения. Конечные точки определяются в приложении и настраиваются при запуске приложения.
{{cite web}}
: CS1 maint: несколько имен: список авторов ( ссылка )