Тема 3. Концепції об'єктно-орієнтованого підходу до розробки великих програмних систем
На сьогоднішній момент об'єктно-орієнтований підхід є одним із таких напрямків в проектуванні систем, що швидко розвивається. Прикладом можуть бути об'єктно-орієнтований аналіз — методологія розробки систем, запропонована Йорденом, об'єктно-орієнтоване проектування, об'єктно- орієнтоване програмування, реалізоване в численних компіляторах C++, Object Pascal, Borland Pascal, Smalltalk.
Не дивлячись на відмінності, які існують в конкретних варіантах об'єктно-орієнтованого підходу, всі ці варіанти об'єднуються декількома основоположними принципами:
- Інкапсуляція - така властивість, при якій об'єкти містять опис атрибутів і дій одночасно;
- Успадкування - такий метод визначення об'єктів, при якому похідні об'єкти (нащадки) успадковують властивості (атрибути і дії) від своїх батьків;
- Поліморфізм - така властивість об'єктів, при якій дії з однаковими іменами викликають різну поведінку для різних об'єктів.
Основна перевага об'єктно-орієнтованого підходу полягає в тому, що задача вирішується новим способом. Замість формування набору процедур, які призначені для вирішення конкретної задачі, формується набір об'єктів, які властиві даній предметній області. Якщо такий набір складається грамотно, то не тільки конкретна задача може бути вирішена, але й потенційно закладається фундамент для вирішення всіх задач в даній предметній області. Звичайно при структурному програмуванні такий підхід стихійно складався при розробці програм у виді бібліотек підпрограм за темами. Але об'єктно-орієнтований підхід дає нові механізми, перераховані вище (3 основні властивості об'єктно- орієнтованого підходу), які дозволяють створювати дійсно незалежний від задачі опис предметної області в виді набору об'єктів.
Одним із джерел помилок у процедурних мовах програмування є передача неправильних параметрів в підпрограми. При передачі параметрів в підпрограму компілятор може проконтролювати синтаксичну сумісність типів, але не семантику. Наприклад, підпрограма має параметр типу "ціле число", який позначає температуру води, але в якості фактичного значення в неї можна передати будь-яке ціле число, наприклад, 10000, яке не може бути температурою води. Прослідкувати такого роду помилки дуже не просто, особливо якщо врахувати, що семантична помилка може бути набагато тоншою і може не контролюватися простим попаданням числа в заданий діапазон. Зменшення ймовірності таких помилок полягає в синтаксичному зв'язуванні даних з діями. Мається на увазі дані, які передаються як фактичні параметри в підпрограми. Так появилось поняття абстрактного типу даних.
Інкапсуляція виникла як логічне продовження ідеї абстрактних типів даних, в якій кожен тип має деяку, іноді недоступну ззовні внутрішню структуру і набір завжди доступних операцій над змінними даного типу. Тобто на відміну від звичайних підходів до типів, коли тип повністю визначається тільки структурою зберігання інформації, абстрактний тип додатково визначається набором операцій. Перевагою такого підходу полягає в виключенні помилок, які полягають в застосуванні операцій, що недопустимі для типу даних, більшої універсальності, коли можна міняти внутрішню структуру зберігання даних без необхідності зміни інших частин системи.
Розглянемо ці особливості на наступному прикладі. Нехай розробляється бібліотека підпрограм для роботи з матрицями. Нехай вибрано зберігання у виді двомірного масиву. При необхідності переходу до розрідженого зберігання доведеться змінювати будь-яке визначення даних для звернення до бібліотеки. Якщо ж матриця визначена як абстрактний тип даних з операціями, то зміна методу зберігання матриці не вплине на інші частини програми.
Об'єкт, який має властивості інкапсуляції характеризується наступними параметрами:
- Унікальне ім'я;
- Набір атрибутів - даних, які характеризують стан об'єкту;
- Набір дій (методів) для зміни своїх станів, тобто для опису своєї поведінки.
Розглянемо характерний опис об'єкту:
Об'єкт: точка
Атрибути: позиція на площині
Методи: створити, вилучити, перемістити в нову позицію, відобразити,
Стерти.
Об'єкт: прилад
Атрибути: покази
Методи: зняти покази.
Кожен об'єкт, заданий іменем, атрибутами і методами представляє собою замкнуту сутність, яка однозначно визначена для стороннього спостерігача. Принципова особливість такого об'єкту полягає в тому, що він може робити тільки те, що визначено в якості його методів і все, що визначено в якості методів об'єкта, об'єкт виконує самостійно. Не говорять "перемістити (об'єкт)", а говорять "об'єкт перемістись". Це забезпечує всі властивості абстрактного типу даних.
У реальному світі успадкування об'єктів можна розглядати в двох аспектах. З одного боку - це успадкування виду "являється", з іншого боку - виду "складається з".
Успадкування виду "являється" передбачає, що об'єкт-нащадок повністю включає в себе всі властивості об'єкта-батька.
Успадкування властивостей в об'єктно-орієнтованому підході розуміється як успадкування атрибутів і методів, тобто можливість використання в похідному об'єкті атрибутів і методів базового об'єкту. Нехай є два об'єкти:
Об'єкт: геометрична фігура атрибути: позиція на площині
Методи: створити, вилучити, перемістити в нову позицію, зобразити,
Стерти
Об'єкт: прямокутник атрибути: висота, ширина методи: створити, зобразити.
Нехай об'єкт прямокутник є нащадком об'єкта геометрична фігура. Тоді прямокутник має три атрибути: позиція, висота, ширина і п'ять методів поведінки. Серед них атрибут позиція успадковується від об'єкту "геометрична фігура", а атрибути висота і ширина - власні. Методи Створити і Зобразити перевизначаються в об'єкті Прямокутник, в той же час, як інші успадковуються (тобто до них можна звернутися). Успадкування забезпечує можливість абстрагування від всіх властивостей об'єкта при його опису, і дає можливість зосередитись тільки на тих унікальних властивостях, які притаманні об'єкту безпосередньо. На практиці це приводить до того, що з'являється можливість легкої модифікації властивостей цілої групи об'єктів за рахунок однієї зміни. Наприклад, якщо до об'єкта геометрична фігура добавити атрибут колір, то всі похідні об'єкти (а в реальній задачі їх може виявитися декілька десятків: прямокутник, коло, дуга і т.п.) Відразу ж отримують цей додатковий атрибут.
Поліморфізм передбачає можливість однакового іменування різних дій. Ця особливість має два аспекти:
- Можливість однакового іменування статичних методів;
- Можливість однакового іменування динамічних методів.
Нехай є два об'єкти геометрична фігура і прямокутник. В обох об'єктах визначені методи "намалювати". Ці методи мають однакові імена, але виконують різні дії, в залежності від варіанту виклику:
- Геометрична фігура. Намалювати;
- Прямокутник. Намалювати.
Це приклад статичного поліморфізму. Його реалізовувати і осмислити легко за рахунок того, що виклик кожного методу супроводжується іменем об'єкта.
Розглянемо тепер метод перемістити для геометричної фігури. Нехай цей метод повинен виконувати переміщення зображення об'єкту на площині. Його реалізація на змістовому рівні може бути такою:
1. Стерти об'єкт в поточній позиції,
2. Змінити позицію об'єкта,
3. Намалювати об'єкт в новій позиції.
Дії 1 і 3 реалізуються за допомогою методів стерти і намалювати, а дія 2 - за допомогою присвоєння нового значення. Потрібно звернути увагу на те, що ця послідовність дій однакова для всіх об'єктів, які успадковують свої властивості від об'єкта геометрична фігура. Відмінність тільки в тому, що методи стерти і намалювати повинні викликатися для того об'єкта, який викликав метод перемістити. Це варіант динамічного поліморфізму, який в мовах програмування реалізується за допомогою віртуальних функцій.
Інкапсуляція є визначальним елементом об'єктно-орієнтованого підходу. Це зв'язане з тим, що саме ця властивість змінює стиль і психологію розробки систем. При створенні процедурних програм необхідно оперувати такими поняттями як дії. Наприклад, при розробці програми спочатку проробляється структура головної програми. Одночасно з цим може проробляється структура незалежних бібліотек підпрограм, які незалежать від головної задачі. Але у будь-якому випадку ми думаємо про дії, алгоритми і, в кращому випадку про параметри підпрограм.
Коли розробляється об'єктна програма, необхідно забути про конкретну задачу і сконцентруватися на об'єктах предметної області, тобто тієї області для якої створюється програма. Нехай в якості задачі формулюється створити графічний редактор. При процедурному підході проектується набір підпрограм, наприклад "Намалювати точку", "Намалювати прямокутник", "Намалювати коло", "Перемістити точку", "Вилучити невидимі лінії", "Вивести вміст екрану на принтер", "Команда зберегти файл" і т.п. Якщо створення об'єктної програми ведеться за тими ж принципами, то вона буде набагато гірша, ніж звичайна процедурна програма. За рахунок того, що самі собою властивість об'єктів (наприклад, інкапсуляція) не дають жодних переваг. Ці переваги реалізуються тільки при вмілому визначенні об'єктів. Розглянемо такий приклад. Необхідно створити об'єкт для представлення хеш-таблиці, яка зберігає прізвища, імена студентів групи. Варіант 1:
Тип: елемент хеш-таблиці
Атрибути: прізвища : стрічка, ім'я : стрічка, по-батькові : стрічка, група : стрічка
Об'єкт: хеш-таблиця
Атрибути: масив елементів типу елемент хеш-таблиці, кількість елементів
Методи: вставити елемент (елемент : елемент хеш-таблиці), вилучити елемент (прізвище : стрічка), обчислити хеш-функцію (прізвище : стрічка)
У цьому варіанті визначається тип елемента хеш-таблиці, як деякий структурний тип. Далі визначається об'єкт хеш-таблиця, яка зберігає елементи заданого типу. Дане визначення досить працездатне, але перекреслює всі переваги об'єктного підходу, так як в майбутньому ніякої зміни поведінки хеш- таблиці зробити неможна. Розглянемо інше визначення. Варіант 2:
Об'єкт: елемент хеш-таблиці атрибути: ключ : стрічка об'єкт: хеш-таблиця
Атрибути: масив елементів типу елемент хеш-таблиці, кількість елементів
Методи: вставить елемент (елемент : елемент хеш-таблиці), вилучити елемент (прізвище : стрічка), обчислити хеш-функцію (прізвище : стрічка)
Об'єкт: елемент хеш-таблиці
Атрибути: прізвище : стрічка, ім'я : стрічка, по-батькові : стрічка, група : стрічка
В даному визначенні елемент хеш-таблиці став об'єктом. За рахунок цього з'явилась можливість його розширювати за рахунок наступної властивості об'єктно-орієнтованого підходу - успадкування. А за рахунок третьої властивості - поліморфізму, будь-який похідний об'єкт може бути вставлено в таблицю за допомогою методу "вставити елемент".
Під об'єктами розуміють деяку абстрактну сутність, задану набором імен атрибутів і імен методів поведінки. Але об'єкт не має жодного конкретного стану, так як його атрибути не мають значень. Значення мають лише конкретні екземпляри об'єктів. У деяких задачах принципово підкреслити характер відношень між об'єктом і його екземплярами. Прикладами таких відношень є:
А) об'єкт не може мати екземплярів;
Б) об'єкт може мати тільки один екземпляр в межах даної задачі;
В) об'єкт може мати багато екземплярів.
Можливість контролю допустимої кількості екземплярів об'єкту збільшує надійність системи за рахунок виключення помилок при створенні недопустимих екземплярів.
Використання успадкування часто викликане необхідністю досягнути одну з наступних цілей:
- Побудови принципово нового об'єкта, який базується на властивостях існуючого.
- Розширення і зміни функціональності наявного об'єкту.
У першому випадку, прикладом може бути побудова об'єктів "Прямокутник", "Ромб", "Еліпс", на основі об'єкту "Геометрична фігура", а ілюстрацією для другого пункту є створення об'єкту "Прямокутник з товстою лінією", шляхом модифікації об'єкту "Прямокутник".
Варіант побудови нового об'єкта, передбачає введення специфічних атрибутів і методів, тоді як модифікація в першу чергу базується на властивості поліморфізму.
Звичайний варіант успадкування в об'єктно-орієнтованому підході - успадкування типу "являється". Типи об'єкту-нащадка і об'єкта-батька у цьому випадку мають одну природу і є порівнюваними. У об'єкта є один батько.
Можливий також випадок множинного успадкування, при якому новий об'єкт включає всі атрибуту і методи декількох батьківських об'єктів типу які можуть бути не порівнюваними. Тип об'єкта-нащадка у цьому випадку може бути приведено до будь-якого з батьківських типів. Проте, використання такого виду успадкування при проектуванні і розробці програмних систем не
Рекомендується через його складністю.
Іноді потрібно, щоб знову створюваний об'єкт складався з декількох компонентів. Такий тип взаємодії називають композицією, або успадкуванням "складається з", хоча з точки зору об'єктно-орієнтованого підходу це не є успадкуванням в чистому виді. Типи нащадка і складових його об'єктів при цьому можуть бути не порівнюваними. Частіше за все, такий вид взаємодії реалізується шляхом включення вихідного об'єкта (об'єктів) в якості атрибутів нового об'єкта.
Переваги та недоліки об'єктно-орієнтованого підходу
Необхідно явно розділяти дві категорії об'єктно-орієнтованого підходу: об'єктно-орієнтоване програмування (тобто методика складання текстів програм на об'єктно-орієнтованій мові) і об'єктно-орієнтований аналіз і проектування (тобто створення проектів систем і опис предметної області в термінах об'єктно- орієнтованого підходу - класів, атрибутів, методів).
Сьогодні ні в кого не виникає сумнівів у тому, що об'єктно-орієнтоване програмування є найбільш прогресивною технологією розробки програмних систем.
Об'єктно-орієнтований аналіз, як засіб опису предметної області і об'єктно-орієнтоване проектування як спосіб створення високорівневих проектів сьогодні піддаються критиці. Одним із результатів цієї критики є створення універсальної мови моделювання - UML.
Переваги об'єктно-орієнтованого підходу:
- Скорочення кількості можливих помилок. Типові помилки при вирішенні різноманітних задач:
- Неузгоджені параметри підпрограм;
- Неузгодженість змін атрибутів.
- Повторне використання. Передбачається деякий варіант багаторазового використання вже існуючого проекту або його частин в новому проекті. Повторне використання можна розділити на дві категорії:
- Повторного використання існуючого коду для вирішення модифікованої задачі;
- Повторне використання і для вирішення інших задач в даній предметній області.
У обох випадках об'єктно-орієнтований підхід дає переваги. За рахунок використання класів легко модифікувати існуючі елементи без зміни вже готових.
Недоліки об'єктно-орієнтованого підходу:
- Ускладнення методології. Застосування об'єктно-орієнтованого підходу потребує введення додаткових способів представлення інформації про предметні області і методів її аналізу. Мова UML включає більше 100 різних умовних позначень. Для успішного використання подібного механізму потрібно наявність певного рівня кваліфікації в спеціалістів. Для невеликих проектів більш ефективним може виявитися застосування класичних методів розробки. Розробка проектів, для яких важливо. Задачею є опис предметної області, і для яких неможливо знайти людину, яка б розуміла цю предметну область в цілому також потребує використання традиційних підходів, через їх більшу доступність для неспеціалістів.
Складність реалізації. Об'єктно-орієнтовані проекти і їх програмні реалізації об'єктно-орієнтованою мовою, потребують більших часових затрат і приводять до побудови більш складної і вимогливої до ресурсів програми, ніж класичні методи, які можуть виявитися більш ефективними для деяких задач.