Давайте попробуем понять это на двух примерах.
Пример 1
В прежние времена приложения, используемые для генерации командных приглашений, принимали пользовательские вводы один за другим Сегодня фреймворки пользовательского интерфейса создают экземпляры различных элементов пользовательского интерфейса, перебирая различные события этих элементов пользовательского интерфейса (например, наведение мыши, щелчок и т. Д.), А пользовательские / основные программы предоставляют хуки (например, прослушиватели событий пользовательского интерфейса в Java) для прослушивания этих событий. Таким образом, основной поток элементов управления «контроль» перемещается из пользовательской программы в среду пользовательского интерфейса. В прежние времена это было в пользовательской программе.
Пример 2
Рассмотрим класс CustomerProcessor
ниже:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Если я хочу processCustomer()
быть независимым от какой-либо реализации getAllCusts()
, а не только от той, которая предоставлена SqlCustRepo
, мне нужно будет избавиться от строки: SqlCustRepo custRepo = new SqlCustRepo()
и заменить ее чем-то более общим, способным принимать различные типы реализаций, так что они processCustomers()
будут просто работать для любая предоставленная реализация. Вышеупомянутый код (создание необходимого класса с SqlCustRepo
помощью логики основной программы) является традиционным способом, и он не достигает этой цели отделения processCustomers()
от реализации getAllCusts()
. При инверсии управления контейнер создает экземпляр необходимого класса реализации (как указано, скажем, в конфигурации xml), внедряет его в логику основной программы, которая связывается в соответствии с указанными хуками (скажем, с помощью @Autowired
аннотации или getBean()
метода в среде Spring).
Посмотрим, как это можно сделать. Рассмотрим код ниже.
Config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="custRepo" class="JsonCustRepo" />
</beans>
CustRepo.java
interface ICustRepo
{ ... }
JsonCustRepo.java
class JsonCustRepo implements CustRepo
{ ... }
App.java
class App
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
}
}
Мы также можем иметь
class GraphCustRepo implements ICustRepo { ... }
а также
<bean id="custRepo" class="GraphCustRepo">
и нам не нужно будет менять App.java.
Над контейнером (который является платформой Spring) лежит ответственность за сканирование XML-файла, создание экземпляра bean-компонента определенного типа и внедрение его в пользовательскую программу. Пользовательские программы не имеют контроля над тем, какой класс создается.
PS: IoC является общей концепцией и достигается многими способами. Приведенные выше примеры достигают этого путем внедрения зависимости.
Ссылка: статья Мартина Фаулера .