Спробуємо зрозуміти це через два приклади.
Приклад 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()
методом у весняній рамці).
Давайте подивимось, як це можна зробити. Розглянемо нижче код.
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.
Над контейнером (який є весняним фреймом) несе відповідальність за сканування файлу xml, інстанціювання файлу конкретного типу та введення його в користувальну програму. Користувацька програма не має контролю над тим, який клас інстанціюється.
PS: IoC - це загальна концепція, яка досягається багатьма способами. Наведені вище приклади досягають цього шляхом введення залежності.
Довідка: стаття Мартіна Фаулера .