You are on page 1of 17

Державний університет «Одеська Політехніка»

Інститут комп’ютерних систем


Кафедра інформаційних систем

Реферат
з дисципліни «Технології комп'ютерного проектування»

Тема: «The Spring framework: IoC контейнер на прикладі UML»

Виконала:
студентка групи АИ-202
Полянський М.О.
Перевірив:
Іванов О. В.

Одеса 2022
ЗМІСТ
1. Архітектура..................................................................................................................3
2. Прямий потік керування.............................................................................................4
3. Інверсія потоку керування..........................................................................................5
4. Коли без IoC не обійтися............................................................................................8
5. Чи є модель подій синонімом IoC?..........................................................................10
6. Бібліотеки та каркаси................................................................................................10
7. Технічна реалізація IoC.............................................................................................11
ВИСНОВОК...................................................................................................................13

2
Spring це досить популярний opensource проект, що охоплює багато аспектів
як J2EE, так і Java розробок

1. Архітектура
Архітектура Spring представлена наступною схемою:

Малюнок 1 Схема Spring

В основі Spring лежить патерн Inversion of control. Стосовно легковажних


контейнерів, основна ідея цього патерну полягає в усуненні залежності
компонентів або класів програми від конкретних реалізацій допоміжних
інтерфейсів та делегуванні повноважень з управління створенням потрібних
реалізацій IoC контейнеру.

3
2. Прямий потік керування
Ось як виглядатиме архітектура цієї системи без застосування принципу
IoC, тобто direct control. У цій архітектурі буде передбачено лише перший аспект
масштабування.

Малюнок 3

Точки входу перебувають у компонентах Принтер_ММВБ і


Принтер_РТС. На виході ці компоненти даватимуть exe-файли, які нам і
потрібні. Компонент Графік відповідає візуальному уявленню графіка біржового
індексу. Точки входу – це методи Main (args: string []). Швидше за все, компонент
Принтер_ММВБ та Принтер_РТС матимуть загальну логіку, тому вводимо
компонент Принтер, спадкоємцями якого вони будуть.

Опишу, як працює ця архітектура. Для прикладу розглядатимемо компонент


Принтер_ММВБ. Ось те, що знаходиться в Принтер_ММВБ.Main(args : string[]):

Main(string[] args)

Принтер_ММВБ принтер_ММВБ = new Принтер_ММВБ();


ДанныеГрафика данныеГрафика = принтер_ММВБ.ПолучитьДанные();
ГенераторГрафиков генераторГрафиков = new ГенераторГрафиков();

График график = генераторГрафиков.ПолучитьГрафик(данныеГрафика, "ММВБ");


график.Напечатать();
4
Тепер розглянемо перший аспект масштабування. Додавання нового
біржового індексу ІНД вимагатиме додавання нового компонента Принтер_ІНД.
Усі інші компоненти системи мають залишитися без змін. Таким чином, у
контексті першого аспекту масштабування систему можна розділити на динамічні
та статичні компоненти. У контексті першого аспекту масштабування
динамічними компонентами є Принтер_ММВБ і Принтер_РТС. Статичними
компонентами є всі інші компоненти: Дані Графіка, Генератор Графіків, Графік та
Принтер. Потік керування спрямований від динамічних компонентів до
статичних. Це і є визначення прямого потоку керування.

5
3. Інверсія потоку керування

Ось як виглядатиме архітектура цієї системи після інверсії прямого потоку


управління. Як і раніше у цій архітектурі буде передбачено лише перший аспект
масштабування.

Малюнок 4

Перше, що впадає в око – це те, що стрілочок залежностей поменшало.


Зменшилася кількість компонентів, що розділяються: в архітектурі direct control
це були компоненти ДаніГрафіка, ГенераторГрафіків і Графік, при
використанні IoC тільки компонент ДаніГрафіка є розділеним.

Тепер у нас одна точка входу: Принтер. Main (args: string). Тепер у
параметрі args (це аргументи командного рядка) ми будемо передавати назву
індексу (ММВБ або РТС), який потрібно надрукувати.

Опишу, як працює ця архітектура. Ось те, що знаходиться в


Принтер.Main(args : string[]):

Main(string[] args)

{
ПровайдерДанныхГрафика провайдерДанныхГрафика;
if (args[0] == "ММВБ") 6
провайдерДанныхГрафика = new ПровайдерДанныхГрафика_ММВБ();

if (args[0] == "РТС")
Стрілки від компонента Принтер до компонента
ПровайдерДанихГрафіка_ММВБ і від компонента Принтер до компонента
ПровайдерДаннихГрафіка_РТС зроблені нежирними недарма. Вони можуть
взагалі бути відсутніми (або навіть направлені у зворотний бік, якщо дуже
потрібно), якщо в технічній реалізації використовується IoCContainer або патерн
«Factory Method». Виходить, що пов'язаність може зменшуватися не тільки
завдяки самому принципу IoC, але і завдяки його технічній реалізації, але про це
буде сказано нижче. У наведеному вище псевдокод IoCContainer і патерн
«Factory Method» не використовуються, тому стрілки присутні.

На діаграмі немає компонентів ГенераторГрафіків та Графік, але в коді


вони присутні. Це тому, що з використанням IoC з'явилася можливість
інкапсулювати ці компоненти в компонент Принтер, що я зробив для спрощення
структури суперсистеми. Тобто тепер компоненти Генератор Графіків та
Графік стали підкомпонентами компонента Принтер, тому стали ізольовані від
компонентів своєї надсистеми. У цьому полягає спрощення та зменшення
зв'язаності системи (але не тільки в цьому).

А що, якби нам знадобилося використовувати компоненти Генератор


Графіків та Графік у якихось інших системах? Тоді довелося б відмовитися від
інкапсуляції цих компонентів компонент Принтер, а архітектура виглядала б
наступним чином:

7
Малюнок 5
Зауважу, що кількість компонентів, що розділяються, не змінилося.
Тепер розглянемо перший аспект масштабування. Додавання нового
біржового індексу ІНД вимагатиме додавання нового компонента
ПровайдерДанихГрафіка_ІНД. Усі інші компоненти системи мають залишитися
без змін. У контексті першого аспекту масштабування динамічними
компонентами є ПровайдерДанихГрафіка_ММВБ і
ПровайдерДанихГрафіка_РТ С. Статичними компонентами є всі інші
компоненти: ДаніГрафіка, Принтер (ГенераторГрафіків, Графік). Потік
керування спрямований від статичних компонентів до динамічних. Це і є
визначення інверсованого потоку керування.

ПРИМІТКА
З коду видно, що принцип IoC покладається на поліморфізм (один
із трьох принципів ОВП).

4. Коли без IoC не обійтися

Повернемося до архітектури прямого потоку управління (рисунок 3). На


ньому передбачено лише перший аспект масштабування. Змінимо архітектуру
8
так, щоб був передбачений і другий аспект масштабування. Припустимо, що
обставини складаються так, що змінювати візуальний стиль графіків можна тільки
в компоненті Генератор Графіків (хоча логічніше було б це зробити в
компоненті Графік). Ось як виглядатиме архітектура:

Малюнок 6

Обмежусь печаткою одного біржового індексу: ММВБ (РТС можна легко


додати на діаграму, тільки тоді вона вийде перевантаженою). Те, що відображено
на діаграмі малюнка 6 є підсистемою друку графіка ММВБ.

Опишу, як працює ця архітектура. Ось що знаходиться в


Принтер_ММВБ.Main(args : string[]):

Main(string[] args)
{
ПровайдерДанныхГрафика провайдерДанныхГрафика;

if (args[0] == "ММВБ")
провайдерДанныхГрафика = new ПровайдерДанныхГрафика_ММВБ();
if (args[0] == "РТС")
провайдерДанныхГрафика = new ПровайдерДанныхГрафика_РТС();

9
ГенераторГрафиков генераторГрафиков;

if (args[1] == "Цветной")
генераторГрафиков = new ГенераторГрафиков_Цветной();

if (args[1] == "ЧерноБелый")
генераторГрафиков = new ГенераторГрафиков_ЧерноБелый();

ДанныеГрафика данныеГрафика = провайдерДанныхГрафика.ПолучитьДанные();


График график = генераторГрафиков.ПолучитьГрафик(данныеГрафика, args[0]);
график.Напечатать();
}

Тепер проаналізуємо, що вийде при додаванні візуального стилю


відображення графіків. Для цього знадобиться додавання нового «Спадкоємця»
компонента ГенераторГрафіков. Інші компоненти підсистеми повинні
залишитися без змін. У контексті другого аспекту масштабування динамічними
компонентами є ГенераторГрафіков_Кольоровий та
ГенераторГрафіков_ЧорноБілий. З татичними компонентами є всі інші
компоненти: Принтер_ММВБ, Дані Графіка, Графік, Генератор Графіків.
Потік керування спрямований від статичних компонентів до динамічних. За
визначенням, цей потік управління інверсований. А іншого варіанта у нас і немає,
тому що напрямок потоку управління задає надсистема.

Зауважу, що компонент Принтер_ММВБ (і Принтер_РТС) є динамічним у


першому аспекті масштабування та статичним у другому. І суперсистема у
контексті першого аспекту масштабування побудована за принципом Direct
Control, а контексті другого аспекту масштабування її підсистема побудована за
принципом IoC. Зауважу, що питання, за яким принципом побудована
суперсистема в контексті другого аспекту масштабування, некоректний,
оскільки другий аспект масштабування відноситься тільки до підсистеми друку
графіка конкретного біржового індексу.

Стрілки від компонента Принтер_ММВБ до компоненту


ГенераторГрафиков_Кольоровий та від компонента Принтер_ММВБ до
компонента ГенераторГрафиков_ЧерноБілий зроблені нежирними з тієї
причини, з якої зроблені нежирні стрілки на діаграмах малюнків 4 і 5.
10
Повернемося до архітектури інверсованого потоку управління (малюнки 4
та 5). Підтримку другого аспекту масштабування можна додати і в неї,
аналогічно тому, як це зроблено в архітектурі прямого потоку виконання, і ми
також будемо змушені застосувати IoC.

5. Чи є модель подій синонімом IoC?

Не є. Як і IoC, при використанні подій також відбувається інверсія потоку


управління, але інша інверсія. У IoC та подійній моделі відрізняється поняття
прямоти потоку управління. У контексті принципу IoC прямим потоком

11
керування є потік керування від динамічних компонентів до статичних.
Динамічні та статичні компоненти визначені в контексті будь-якого аспекту
масштабування. Поняття аспекту масштабування, динамічних та статичних
компонентів є поняттями, які застосовуються під час проектування (design time).
Події дозволяють інвертувати потік управління під час виконання (run time). І їм
зовсім не важливо, який потік управління вони інвертують: від динамічних
компонентів до статичних або статичних до динамічних.

6. Бібліотеки та каркаси

Чим відрізняється бібліотека (library) від каркасу (framework)? Бібліотека це


статичні компоненти при прямому потоці управління (direct control). Каркас – це
статичні компоненти при інверсованому потоці управління (IoC). Схожа думка
12
простежується у статті Designing Reusable Classes (Ralph E. Johnson & Brian
Foote).

ПРИМІТКА
Подієва модель спирається на можливість передати адресу методу
змінної і викликати цей метод через цю змінну.

7. Технічна реалізація IoC

До цього моменту я писав переважно про теоретичну сторону питання.


Далі опишу, як у практиці реалізується принцип IoC. Принцип IoC реалізується за
13
допомогою шаблону проектування «Factory Method» («Фабричний метод») та
бібліотек IoCСontainer. Опціонально в IoCСontainer дозволяє виконувати ін'єкцію
залежності (Dependency Injection). У програмних кодах, наведених вище, немає
жодного з цих коштів. Як зазначалося, використання цих засобів дозволяє ще
більше зменшити зв'язаність компонентів (на діаграмах малюнків 4, 5, 6 зникнуть
нежирні стрілки залежностей).

Шаблон проектування "Factory Method"

Ось як виглядатиме діаграма малюнка 4 з використанням Factory Method:

Малюнок 7
Тут сміливо можна забрати нежирні стрілки. У компонент
ПровайдерДанихГрафіка додається статичний метод
ОтриматиЕкземпляр(ім'яІндексу: string). Якщо цьому методу як параметр
передати рядок «ММВБ» він поверне «примірник» компонента
ПровайдерДанихГрафіка_ММВБ (аналогічно до інших біржових індексів). Для
цього компонент ПровайдерДанихГрафіка повинен залежати від своїх
спадкоємців. Це недобре, але про це трохи нижче.

14
Опишу на псевдокоді, як працює ця архітектура:

Main(string[] args)
{
ПровайдерДанныхГрафика провайдерДанныхГрафика =
ПровайдерДанныхГрафика.ПолучитьЭкземпляр(args[0]);
ГенераторГрафиков генераторГрафиков = new ГенераторГрафиков();
ДанныеГрафика данныеГрафика = провайдерДанныхГрафика.ПолучитьДанные();
График график = генераторГрафиков.ПолучитьГрафик(данныеГрафика, args[0]);
график.Напечатать();
}

У параметрі args (це аргументи командного рядка) методу Принтер.


Main(args : string[]) передається назву індексу ("ММВБ" або "РТС"), який
потрібно надрукувати.

У цій реалізації є така перевага в порівнянні з реалізацією архітектури,


зображеної на малюнку 4. Припустимо, система реалізована за діаграмою
малюнка 4, і нам знадобилося створити систему для статистичної обробки даних
зміни біржових індексів. Припустимо, у цій системі буде компонент
ОбробникДанихГрафіка. Цей компонент отримує дані зміни біржового індексу у
компонента ПровайдерДанихГрафіка_ММВБ або ПровайдерДаннихГрафік
а_РТС, тобто стає залежним від цих компонентів. Але компоненти
ПровайдерДанихГрафіка_ММВБ або ПровайдерДаннихГрафік а_РТС вже
залежать від компонента Принтер. Таким чином, компоненти
ПровайдерДанихГрафіка_ММВБ і ПровайдерДаннихГрафіка_РТС стають
поділюваними, що збільшує зв'язаність. Якщо ми будемо використовувати патерн
«Factory Method», то компоненти ОброблювачДанихГрафіка та Принтер
залежатимуть тільки від компонента ПровайдерДаннихГрафіка, і тільки він
стане розділеним.

ВИСНОВОК

15
У загальному випадку, IoC-контейнер – це певний програмний код
(фреймворк, окремий клас), який здійснює впровадження залежностей у додатку
та, наскільки це можливо, спрощує цей процес.

Як правило, використання залежності здійснюється через:

• конструктор класу (constructor injection);


• поле класу (field injection);
• вхідний аргумент методу (method injection), тобто через сетер.

Впровадження через статичні поля та методи не рекомендується.


Фреймворк Spring, перш ніж стати функціональною платформою, спочатку
розроблявся як IoC-контейнер для спрощення розробки JavaEE-додатків (рис.2).

IoC контейнер відповідає за створення необхідної реалізації Product для


Consumer. При використанні класу Consumer в інших проектах ми зможемо
замінити реалізацію інтерфейсу Product більш відповідну, не вносячи змін до
коду.

Основні переваги контейнерів IoC:

1. управління залежностями
2. спрощення повторного використання класів чи компонентів
3. спрощення unit-тестування
4. більш "чистий" код (Класи більше не займаються ініціалізацією
допоміжних об'єктів. Не варто, звичайно "перегинати палицю", керуючи
створенням всіх об'єктів через IoC. У IoC контейнер краще всього
виносити ті інтерфейси, реалізація яких може бути змінена в поточному
проекті або у майбутніх проектах.)

Найпоширеніший спосіб визначення залежностей це XML файли


конфігурації (applicationContext.xml). Опис формату цього файлу виходить за
межі цієї статті.

16
Spring набагато більше, ніж просто IoC контейнер. Framework спрощує
розробку J2EE проектів, реалізуючи низькорівневі та найчастіше використовувані
частини корпоративної програми.

17

You might also like