Вітання! Ти коли-небудь думав, чому Java влаштована саме так, як вона влаштована? У тому сенсі, що ти створюєш класи, на їх основі об'єкти, у класів є методи тощо. Але чому структура мови така, що програми складаються саме з класів та об'єктів, а не з чогось іншого? Навіщо було придумано поняття «об'єкт» і поставлено на чільне місце? Чи всі мови влаштовані так і якщо ні, які переваги це дає Java? Запитань, як бачиш, багато :) Спробуємо відповісти на кожен із них у сьогоднішній лекції.
Крістен Нюгор та Оле Йохан Даль - творці Simula
Здавалося б, Simula — давня мова за мірками програмування, але їхній «споріднений» зв'язок із Java видно неозброєним оком. Швидше за все, ти легко прочитаєш написаний на ньому код і загалом поясниш, що він робить:)
Принципи ООП:
Що таке об'єктно-орієнтоване програмування (ООП)
Звичайно, Java не просто так складається з об'єктів та класів. Це не забаганка її творців, і навіть не їхній винахід. Є багато інших мов, основу яких лежать об'єкти. Перша така мова називалася Simula, і її винайшли ще у 1960-х роках у Норвегії. Крім іншого, у Simula з'явабося поняття " клас " і " метод ".Begin
Class Rectangle (Width, Height); Real Width, Height;
Begin
Real Area, Perimeter;
Procedure Update;
Begin
Area := Width * Height;
OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
Perimeter := 2*(Width + Height);
OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
End of Update;
Update;
OutText("Rectangle created: "); OutFix(Width,2,6);
OutFix(Height,2,6); OutImage;
End of Rectangle;
Rectangle Class ColouredRectangle (Color); Text Color;
Begin
OutText("ColouredRectangle created, color = "); OutText(Color);
OutImage;
End of ColouredRectangle;
Ref(Rectangle) Cr;
Cr :- New ColouredRectangle(10, 20, "Green");
End;
Приклад коду взято зі статті Simula - 50 років ООП . Як бачиш, Java і його предок не так сильно відрізняються один від одного :) Це пов'язано з тим, що поява Simula ознаменувала собою народження нової концепції - об'єктно-орієнтованого програмування. Вікіпедія дає таке визначення ООП: Об'єктно-орієнтоване програмування (ООП)— методологія програмування, заснована на представленні програми у вигляді сукупності об'єктів, кожен із яких є екземпляром певного класу, а класи утворюють ієрархію спадкування. Воно, на мою думку, дуже вдале. Ти нещодавно почав вивчати Java, але в ньому навряд чи знайдуться незнайомі тобі слова. Сьогодні ООП — найпоширеніша методологія програмування. Крім Java принципи ООП використовуються у багатьох популярних мовах, про які ти, можливо, чув. Це C++ (його активно застосовують розробники комп'ютерних ігор), Objective-C і Swift (ними пишуть програми для пристроїв Apple), Python (найбільш затребуваний у машинному навчанні), PHP (одна з найпопулярніших мов веб-розробки), JavaScript (простіше сказати, чого на ньому не роблять) та багато інших. Власне, що це за «принципи» ОВП? Розкажемо докладніше.
Принципи ООП
Це є основою основ. 4 основні особливості, які разом утворюють парадигму об'єктно-орієнтованого програмування. Їхнє розуміння — ключ до становлення успішного програміста.Принцип 1. Спадкування
Хороша новина: з деякими з принципів ОВП ти вже знайомий! :) Спадкування нам уже кілька разів зустрічалося в лекціях, і ми встигли з ним попрацювати. Спадкування - механізм, який дозволяє описати новий клас на основі існуючого (батьківського). При цьому властивості та функціональність батьківського класу запозичуються новим класом. Для чого потрібне успадкування і які переваги воно дає? Насамперед — повторне використання коду. Поля та методи, описані в батьківських класах, можна використовувати у класах-нащадках. Якщо у всіх типів автомобілів є 10 загальних полів та 5 однакових методів, тобі достатньо винести їх у батьківський класAuto
. Ти зможеш використовувати їх у класах-нащадках без жодних проблем. Суцільні плюси: і кількісно (менше за код), і, як наслідок, якісно (класи стають набагато простіше). При цьому механізм успадкування дуже гнучкий, і функціональність, що бракує в нащадках, ти можеш дописати окремо (якісь специфічні для конкретного класу поля або поведінка). Загалом, як і у звичайному житті: всі ми чимось схожі на наших батьків, а чимось відрізняємося від них:)
Принцип 2. Абстракція
Це дуже простий принцип. Абстракція означає виділення основних, найбільш значущих показників предмета і навпаки — відкидання другорядних, незначних. Не вигадуватимемо велосипед і згадаймо приклад зі старої лекції про класи. Скажімо, ми створюємо картотеку працівників компанії. Для створення об'єктів «працівник» ми написали класEmployee
. Які характеристики важливі для їхнього опису в картотеці компанії? ПІБ, дата народження, номер соціального страхування, ІПН. Але навряд чи в картці такого типу нам потрібні його зростання, колір очей та волосся. Компанії ця інформація про співробітника ні до чого. Тому для класу Employee
ми задамо змінні String name
, int age
, int socialInsuranceNumber
іint taxNumber
, А від зайвої для нас інформації на кшталт кольору очей відмовимося, абстрагуємося. А от якщо ми створюємо картотеку фотомоделей для агенції, ситуація різко змінюється. Для опису фотомоделі нам дуже важливі зріст, колір очей і колір волосся, а номер ІПН не потрібен. Тому в класі Model
ми створюємо змінні String height
, String hair
, String eyes
.
Принцип 3. Інкапсуляція
З ним ми вже стикалися. Інкапсуляція в Java означає обмеження доступу до даних та можливостей їх зміни. Як бачиш, у його основі лежить слово «капсула». У цю «капсулу» ми ховаємо якісь важливі для нас дані, які не хочемо, щоби хтось змінював. Простий приклад із життя. У тебе є ім'я та прізвище. Їх знають усі твої знайомі. Але вони не мають доступу до зміни твого імені та прізвища. Цей процес, можна сказати, «інкапсульований» у паспортному столі: поміняти ім'я прізвище можна лише там, і зробити це можеш лише ти. Інші «користувачі» мають доступ до твого імені та прізвища «тільки на читання» :) Ще один приклад — гроші у твоїй квартирі. Залишати їх на очах посеред кімнати — не найкраща ідея. Будь-який «користувач» (людина, котра прийшла до тебе додому) зможе змінити кількість твоїх грошей, тобто. забрати їх. Краще інкапсулювати їх у сейфі. Доступ буде тільки в тебе і лише за спеціальним кодом. Очевидні приклади інкапсуляції, з якими ти вже працював, це модифікатори доступу (private
, public
і т.д.), а також гетери-сетери. Якщо поле age
у класу Cat
не інкапсулювати, будь-хто зможе написати:
Cat.age = -1000;
А механізм інкапсуляції дозволяє нам захистити поле age
за допомогою методу-сеттера, в який ми можемо помістити перевірку того, що вік не може бути негативним числом.
Принцип 4. Поліморфізм
Поліморфізм - це можливість працювати з кількома типами так, ніби це один і той самий тип. При цьому поведінка об'єктів буде різною залежно від типу, до якого вони належать. Звучить складно? Зараз розберемося. Візьмемо найпростіший приклад - тварин. Створимо класAnimal
з єдиним методом - voice()
і двох його спадкоємців - Cat
і Dog
.
public class Animal {
public void voice() {
System.out.println("Голос!");
}
}
public class Dog extends Animal {
@Override
public void voice() {
System.out.println("Гав гав!");
}
}
public class Cat extends Animal {
@Override
public void voice() {
System.out.println("Мяу!");
}
}
Тепер спробуємо створити посилання Animal
та привласнити їй об'єкт Dog
.
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.voice();
}
}
Як ти вважаєш, який метод буде викликаний? Animal.voice()
або Dog.voice()
? Буде викликаний метод класу Dog
: Гав-гав! Ми створабо посилання Animal
, але об'єкт поводиться як Dog
. При необхідності він може поводитися як кішка, кінь або інша тварина. Головне - присвоїти посилання загального типу Animal
об'єкт конкретного класу-спадкоємця. Це логічно, адже всі собаки є тваринами. Саме це ми мали на увазі, коли говорабо «поведінка об'єктів буде різною, залежно від того, до якого типу вони належать». Якби ми створабо Cat
об'єкт
public static void main(String[] args) {
Animal cat = new Cat();
cat.voice();
}
метод voice()
вивів би «Мяу!». А що означає «можливість працювати з декількома типами так, начебто це той самий тип»? Це також досить легко. Уявімо, що ми створюємо перукарню для тварин. У нашій перукарні маємо вміти стригти всіх тварин, тому ми створимо метод shear()
(«постригти») з параметром Animal
— твариною, яку ми стригтимемо.
public class AnimalBarbershop {
public void shear(Animal animal) {
System.out.println("Стрижка готова!");
}
}
І тепер ми можемо передавати в метод shear
і об'єкти Cat
, і об'єкти Dog
!
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
AnimalBarbershop barbershop = new AnimalBarbershop();
barbershop.shear(cat);
barbershop.shear(dog);
}
Ось і наочний приклад: клас AnimalBarbershop
працює з типами Cat
і Dog
так, ніби це той самий тип. При цьому й Cat
різна Dog
поведінка: вони по-різному подають голос.