article-spots
article-carousel-spots
programs
Матеріали

Основні принципи ООП

14 січ 2020

Пропонуємо ознайомитися з основними принципами об'єктно-орієнтованого програмування – однієї з найбільш важливих методологій розробки, яка ґрунтується на уявленні про програму як про сукупність об'єктів, кожен з яких є екземпляром певного класу, а класи утворюють ієрархію наслідування.

ІНКАПСУЛЯЦІЯ

Одним з визначальних факторів при проектуванні компонентів програми є приховування внутрішніх даних компоненту і деталей його реалізації від інших компонентів програми та надання набору методів для взаємодії з ним (API). Цей принцип є одним з чотирьох фундаментальних принципів ООП і називається інкапсуляцією.

Правильна інкапсуляція має велике значення з багатьох причин: 

1. Вона сприяє повторному використанню компонентів: оскільки в цьому випадку компоненти взаємодіють між собою лише через їх API і нечутливі до змін внутрішньої структури, вони можуть використовуватись в більш широкому контексті. 

2. Інкапсуляція пришвидшує процес розробки: слабко пов'язані один з одним компоненти (тобто компоненти, чий код якомога менше звертається або використовує код інших компонентів) можуть розроблятися, тестуватися та доповнюватися незалежно. 

3. Правильно інкапсульовані компоненти більш зрозумілі та легше налагоджуються, що спрощує підтримку програми. 

У мові Java інкапсуляція реалізована за допомогою системи класів, які дозволяють зібрати інформацію про об'єкт в одному місці; пакетів, які групують класи по певному критерію, і модифікаторів доступу, якими можна позначити весь клас або його поле чи метод. 

Всього існує чотири модифікатори доступу: 

  • public – повний доступ до сутності (полю або методу класу) з будь-якого пакету; 
  • protected – доступ до сутності лише для класів свого пакету і нащадків класу; 
  • private – доступ тільки всередині класу, в якому оголошена сутність; 
  • неявний модифікатор за замовчуванням (за відсутності трьох явних) – доступ до сутності лише для класів свого пакету. 

Для досягнення правильної інкапсуляції також необхідно надати коректний API для роботи з компонентом. Наприклад, в сеттер для змінної можна включити логіку перевірки значень, які передаються, або не надавати сеттери в класі взагалі, якщо клас повинен бути доступним лише для читання. 

Приклад коректної інкапсуляції класу: 

У наведеному вище прикладі значення змінної name задається при створенні об'єкта і не може бути змінене ззовні, так як сеттер для змінної відсутній. В сеттері для змінної age реалізована перевірка на коректність параметру, який передається і викид виключення при невірному значенні.  

НАСЛІДУВАННЯ 

Наслідування є одним з найвагоміших принципів об'єктно-орієнтованого програмування, оскільки воно дозволяє створювати ієрархічні структури об'єктів. Використовуючи наслідування можна створити загальний клас, який буде визначати характеристики і поведінку, властиві певному набору пов'язаних об'єктів. В подальшому цей клас може наслідуватися іншими, другорядними класами, кожен з яких додаватиме унікальні, властиві лише йому характеристики і доповнюватиме або змінюватиме поведінку базового класу. В термінах Java такий загальний клас називається суперкласом (superclass) або базовим класом (base class), або батьківським класом (parent class), а клас, який його наслідує - підкласом (subclass) або дочірнім класом (child class), або похідним класом. (derived class).

Наслідування реалізує відношення «є» (“is-a”) між суперкласом і підлкасом. Нехай, наприклад, класи Employee та Manager являють собою абстракцію понять «Співробітник» і «Менеджер». Кожний менеджер є також співробітником компанії, в якій він працює, отже клас Manager знаходиться у відношенні “is-a” з класом Employee. Таким чином, з точки зору наслідування, при побудові ієрархії класів, клас Employee буде суперкласом, а клас Manager – дочірнім класом. При цьому клас, який є нащадком якого-небудь класу, може бути суперкласом для одного чи декількох інших класів. Також на відміну від, наприклад, C++, в Java відсутнє множинне наслідування , тобто будь-який клас може мати не більше одного батьківського класу. А всі класи, суперклас котрих явно не вказаний, наслідують клас Object.

Клас Employee у вищезгаданому прикладі, є суперкласом не тому, що він головніший за клас Manager або містить більше функціональності. Насправді, вірно зворотне твердження: функціональність підкласів не вужча, а часто суттєво ширша за функціональність їх батьківських класів. Префікси «супер-» і «під-» прийшли в Java з математики: множина всіх менеджерів міститься в множині всіх співробітників, і, таким чином, є підмножиною множини співробітників. 

Для того, щоб наслідувати якийсь клас в Java, використовується ключове слово extends:

У прикладі вище клас Employee є базовим класом для класа Manager, а клас Manager – підкласом класа Employee. Клас Employee абстрагує базові характеристики для всіх співробітників компанії – ім’я, прізвище, розмір заробітної плати і дату прийому на роботу, а клас Manager доповнює ці характеристики відсотком премії для менеджерів і змінює поведінку методу getSalary() базового класу, використовуючи поліморфізм. 

ПОЛІМОРФІЗМ

Розглядаючи поліморфізм необхідно пам'ятати, що цей принцип нерозривно пов'язаний з іншим принципом ООП – наслідуванням, яке допомагає реалізувати поліморфізм. Візьмемо для прикладу абстрактний клас «Автомобіль», який наслідують два конкретних класи – «Спортивний автомобіль» та «Вантажний автомобіль».

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

Наприклад, загальна для всіх автомобілів дія «завестись» у спортивному автомобілі може бути реалізована шляхом натискання кнопки, а у вантажного - за допомогою ключа. Один результат – різні рішення. В цьому і полягає поліморфізм. 

Більш точно, поліморфізм - один з принципів ООП, який дозволяє викликом перевизначеного методу через змінну батьківського класу отримати поведінку, яка буде відповідати реальному похідному класу, на який посилається ця змінна.

Код наведений вище дає приклад поліморфізму. Спочатку змінній батьківського класу Vehicle присвоюється об'єкт дочірнього класу SportCar. Під час виклику методу start() на консоль буде виведено: "Starting my fancy sport car!"

При подальшому присвоєнні цієї ж змінної об'єкту дочірнього класу Truck і виклику того ж методу start() на консоль виводитиметься: "Starting my heavy truck!"

АБСТРАКЦІЯ

Відносно недавно абстракцію почали виділяти, як самостійний четвертий принцип.

Одне з визначень слова «абстракція», які можна зустріти в сучасних словниках: 

Абстракція (від лат. abstractio — виокремлення, відсторонення або відділення) — теоретичний прийом дослідження, який дозволяє відсторонитися від деяких несуттєвих, у певному сенсі, властивостей досліджуваних явищ і виокремити суттєві та визначальні властивості. 

Всі мови програмування пропонують їх користувачу деякі абстрації. Так мови групи асемблер є свого роду абстракцією відповідних мікропроцесорів, оскільки дозволяють відволіктися від деталей їх реалізації та звертатися до них через набір більш високорівневих інструкцій. Імперативні мови програмування, які з'явилися після асемблеру, наприклад Basic, Fortran, C, є більш високим рівнем абстракції над асемблерними мовами – вони дають можливість використовувати більш звичні для людини синтаксичні конструкції за рахунок наближення синтаксису до природніх мов. Об'єктно-орієнтовані мови, такі як Java, виводят розробку на ще вищий рівень абстракції: об'єкти в ООП являють собою моделі понять оточуючого світу, такі як Працівник, Сервер, Запис в щоденнику, і виділяють лише властивості цих понять, необхідні в конкретному випадку для вирішення конкретної проблеми. Наприклад, клас Student в програмі обліку студентів університету, крім загальних полів, таких як ім'я, прізвище, дата народження і т.д., міститиме поля, які відображають інформацію про номер залікової книжки, статус студента (дійсний, академічна відпустка, відраховано), факультет, номер його групи, оцінки за семестр і т. ін. Але для такого ж класа Student в програмі обліку студентів у тренінг-центрі ЕРАМ така інформація буде неактуальна: клас міститиме поля, які відображають навчальний проект, на який був розподілений студент, рівень його англійської мови за результатами останнього тестування, кількість відвіданих заходів та ін.

В цьому і полягає абстракція: фокусування розробника на конкретних властивостях об'єкта залежить від тих задач, які повинен вирішувати об'єкт. Наслідком такого підходу є те, що, якщо в імперативних мовах програмісту необхідно думати в термінах комп'ютерної логіки, то в об'єктно-орієнтованих мовах розробник думає в термінах проблемної сфери, в якій він розробляє програму.