Об’єктно-орієнтований підхід в програмуванні: поняття, застосування і розробка

Першими мовами програмування були імперативні мови, або машинні інструкції (коди). Вони складалися з двійкового коду, який відрізнявся в залежності від машини. Набір можливих команд для таких низькорівневих «мов» був невеликий, так як кожна машинна інструкція виконувала певну дію (додавання, копіювання машинного слова в регістрі, перехід до наступної ділянки коду). Звичайно ж, для зручності програмісти розробили набір буквених аналогів для цих машинних команд, і такий спосіб спілкування з машинним «залізом» отримав назву мову асемблера.

Асемблер

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

Найвідоміші реалізації асемблера:

  • Borland Turbo Assembler (TASM).
  • Microsoft Macro Assembler (MASM).
  • Watcom Assembler (WASM).
  • A86.

Мови високого рівня

З розвитком процесорів виникла необхідність у більш універсальних і широко застосовуваних інструментів для взаємодії з комп’ютером. З часом машинні коди стали дуже довгі і незручні для розуміння, тому було вирішено оперувати командами, інтуїтивно зрозумілими людині, читає і пише код. Першим високорівневим мовою для ЕОМ, використовував такий підхід, став Фортран. Машинні команди перетворилися в читабельні: OPEN, CLOSE, PRINT, тут вперше з’являється блоковий оператор IF і такі конструкції, як IF THEN — ELSE.

Більш того, варто відзначити, що Фортран після відходу перфокарт на смітник історії став підтримувати структурне програмування.

Структурне програмування

У 1960 — початку 1970 років починається розвиток наступної парадигми програмування — структурне програмування, ще один крок до об’єктно-орієнтованого підходу в проектуванні. Після роботи Едгара Дейкстри «Про шкоду оператора goto» у розробників того часу приходить розуміння, що роботу будь-якої програми можна описати, використовуючи тільки три керуючі структури:

  • послідовність;
  • розгалуження;
  • цикл.

Оператор goto з тих пір визнаний надлишковим. Це оператор, що дозволяє перейти до будь-якого блоку програми. І початківцям часом здається, що немає нічого простіше, ніж використовувати оператор goto в певних ділянках коду, щоб не вигадувати чергові галуження і цикли. Але на ділі, використання даного оператора рано чи пізно призводить до того, що програма перетворюється в «спагетті-код». Такий код неможливо підтримувати, безболісно модифікувати, і що найгірше, він важкий для сприйняття інших розробників, які прийдуть на зміну авторові коду. Це особливо небезпечно в бізнес-девелопменті, де проектуються великі бази даних на тисячі рядків коду. Плинність є завжди, і розбиратися з поганим кодом важко, особливо прибулим у компанію програмістам.

The C Programming Language

Розквіт структурного програмування нерозривно пов’язаний з мовою програмування C. Ця мова був написаний на мові асемблера Деннісом Рітчі і Кеном Томпсоном і став вихідним мовою при розробці операційної системи UNIX. Вона стала основою для багатьох сучасних операційних систем, таких як GNU/Linux, FreeBSD, MacOS, Posix і багато інших.

Завдяки тому, що дизайн мова C близький до машинним командам, він отримав широке розповсюдження, в основному в різному прикладному ПЗ для безлічі пристроїв, від відеокарт і операційних систем до ракет і суперкомп’ютерів. А синтаксис назавжди став основою для багатьох сучасних мов програмування (С++, C#, Java, Objective-C).

Об’єктно-орієнтоване програмування (ООП)

Програми продовжували ускладнюватися, і на зміну імперативної парадигми приходить розуміння необхідності об’єктно-орієнтованого підходу до інформаційних технологій. Замість звичної роботи з комп’ютером за допомогою консолі з’являються графічні додатки. Комп’ютер тепер не вузькоспеціалізований апарат для наукових і військових розрахунків, а інструмент, можливості якого простягаються від автоматизації бізнесу до спілкування з друзями.

Основною структурною одиницею при розробці об’єктно-орієнтованим підходом оголошується клас. Клас — це абстрактний тип даних, створений програмістом. Це схема, або контракт, що описує поля і методи об’єктів, які будуть створені за лекалами цього класу.

Наприклад, людина, машина, департамент — це абстракція, значить, її можна описати у вигляді класу. Іван Іванович, біла “Шкода” з номерами нн123, операційний департамент — це конкретні представники даних абстракцій, тобто, говорячи мовою об’єктно-орієнтованого підходу до програмування, це об’єкти даних класів. Завдання розробника — описати абстрактні і конкретні об’єкти реального світу мовою ООП. Опис класу реалізується в описі полів і методів.

Поля

Поля — це змінні, тобто величини, що характеризують роботу даного класу. Наприклад, якщо ми пишемо клас «Машина» для комп’ютерної гри, ми можемо визначити для нього наступні поля:

class Car
{
string brand = “Hunday” Solaris”;
string colour = “Yellow”;
double speed = 0;
/*…решті код програми…*/
}

Приклади коду написані на псевдокоде з C-подібним синтаксисом.

Інкапсуляція

Поля можуть змінювати свої значення в ході виконання програми, якщо це передбачено програмістом. Якщо автор не хоче, щоб поля були доступні поза класу, і якась інша програма (користувач) могла змінити їх значення, то він «інкапсулює дані, тобто робить їх недоступними, використовуючи ключові слова private, protected. Якщо ж поля повинні бути доступні у всій програмі, то перед ними ставиться доступ public.

Наприклад, можна зробити всі поля класу публічними:

class Car
{
public string brand;
public string colour;
public double speed;
*
…решті код програми…
*
}

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

class MainClass
{
public static void Main()
{
Car car = new Car();
car.colour = “Red”;
/* …решті код програми…*/
}
}

Щоб уникнути випадкового зміни даних, розробник інкапсулює їх. У випадку з кольором машини замість public необхідно написати private. Тоді зміна кольору безпосередньо буде зробити неможливо.

Методи

Методи — це функції, що дозволяють оперувати з полями класу або з якимись іншими даними. Як і будь-які функції у процедурних мовах програмування, вони беруть дані, і можуть або повертати результат обчислень, або не повертати (наприклад, виводити щось на консоль). Наприклад:

class Car
{
public string brand = “Hunday” Solaris”;
public string colour = “Yellow”;
public double speed = 0;

/*нижче описаний метод «Drive», який передається булевська мінлива whatIsTrafficLight (зі значеннями тільки false – червоне світло, або true – зелений світло, тобто можна їхати)
public void Drive(bool whatIsTrafficLight)
{
if (whatIsTrafficLight == true)
{
speed = speed + 40;
}
else
{
speed = 0;
}
}

}

У підсумку за допомогою методу Drive ми змінюємо швидкість класу «Машина». Але насправді, у цій розробці, перед програмістом стоїть кілька непростих завдань. По-перше, зробити код підтримуваним.

Поліморфізм

Другий «стовп» розробки об’єктно-орієнтованим підходом — поліморфізм. Бьерн Страуструп, творець мови C++, сформулював визначення поліморфізму так: «Один інтерфейс — багато реалізацій». Коротенько, поліморфізм — це можливість створювати абстрактний клас, який описує загальну конструкцію структури, а від нього вже створюються похідні класи, що реалізують відсутні механізми. Наприклад, при створенні персонажа комп’ютерної гри, з точки зору об’єктно-орієнтованого підходу, логічно буде спочатку реалізувати абстрактний клас Person, і від нього вже створювати конкретні класи: Archer, Healer, Warrior і так далі.

Або ще приклад з машиною. Якщо ми оперуємо однією машиною, з кількома полями і методами, нам нічого не варто вручну поміняти кілька значень в коді. Але скільки може бути таких машин? Або, наприклад, користувачів в соціальній мережі? У кожного є ім’я, прізвище, сімейний стан, фотоальбом, величезна кількість значень, посилань на інші сторінки, на інших користувачів і так далі. І якщо розробники соціальної мережі вирішать зробити редизайн, і якісь параметри користувача змінити чи прибрати, то з таким підходом виникне велика кількість роботи. Вирішує цю проблему об’єктно-орієнтований підхід. Класи створюються не для кожного конкретного об’єкта, а спочатку проектується абстрактний клас, і від нього створюються класи-спадкоємці. Як і інкапсуляція, це друге найважливіше правило ООП.

Спадкування

Спадкування — ще одне правило при використанні об’єктно-орієнтованого підходу. Воно полягає в здатності класу-спадкоємця використовувати можливості класу-батька. Наприклад, якщо ми в нашому автопарку захочемо мати ще й мотоцикл, то не обов’язково писати для нового класу однакові властивості. Замість цього можна сказати, що мотоцикл є класом-спадкоємцем від машини. Тоді стає можливим використовувати схожі поля і методи машини в класі мотоцикла, наприклад, марку, колір, швидкість. У коді спадкування позначається так:

class Motocycle : Car
{
/*…решті код програми…*/
}

Тепер поля і методи класу-батька Car доступні для використання у класі-спадкоємці Motorcycle.

Коротенько, спадкування — це механізм повторного використання коду, і націлений на зручне і логічно грамотне розширення програми. Також спадкування допомагає дотримуватися принципу DRY (Do not Repeat Yourself). Згідно з цим принципом в коді не повинно бути повторюваних ділянок, адже це створює зайве навантаження при компіляції та виконання програми. Якщо в коді є повторювані ділянки, значить, його треба оптимізувати — винести повтори в окремі методи, і викликати їх по потребі; застосувати спадкування до логічно подібним об’єктам, у яких є ідентичні поля та методи.

Резюме

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

  • Спадкування.
  • Поліморфізм.
  • Інкапсуляція.
  • Добре вивчивши ці потужні інструменти, сучасний розробник зможе писати швидкий, підтримуваний, візуально приємний і модифікується код, який довгі роки буде підтримувати потреби бізнесу, приносити радість геймерам, вирішувати соціальні проблеми людей або забезпечувати комунікацію у всіх куточках світу.