JavaRush/Java блог/Random UA/Принципи ООП

Принципи ООП

Стаття з групи Random UA
учасників
Вітання! Ти коли-небудь думав, чому Java влаштована саме так, як вона влаштована? У тому сенсі, що ти створюєш класи, на їх основі об'єкти, у класів є методи тощо. Але чому структура мови така, що програми складаються саме з класів та об'єктів, а не з чогось іншого? Навіщо було придумано поняття «об'єкт» і поставлено на чільне місце? Чи всі мови влаштовані так і якщо ні, які переваги це дає Java? Запитань, як бачиш, багато :) Спробуємо відповісти на кожен із них у сьогоднішній лекції.

Принципи ООП:

  1. успадкування
  2. Абстракція
  3. Інкапсуляція
  4. Поліморфізм

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

Звичайно, Java не просто так складається з об'єктів та класів. Це не забаганка її творців, і навіть не їхній винахід. Є багато інших мов, основу яких лежать об'єкти. Перша така мова називалася Simula, і її винайшли ще у 1960-х роках у Норвегії. Крім іншого, у Simula з'явабося поняття " клас " і " метод ". Принципи об'єктно-орієнтованого програмування.
Крістен Нюгор та Оле Йохан Даль - творці Simula
Здавалося б, Simula — давня мова за мірками програмування, але їхній «споріднений» зв'язок із Java видно неозброєним оком. Швидше за все, ти легко прочитаєш написаний на ньому код і загалом поясниш, що він робить:)
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поведінка: вони по-різному подають голос.

Причини появи ОВП

Чому взагалі виникла ця нова концепція програмування – ОВП? У програмістів були інструменти, що працюють: наприклад, процедурні мови. Що ж спонукало їх винаходити щось нове? Насамперед ускладнення завдань, які перед ними стояли. Якщо 60 років тому завдання програміста виглядало як "обчислити математичне рівняння таке-то", зараз вона може звучати як "реалізувати 7 різних кінцівок для гри STALKER в залежності від того, які рішення приймав користувач в ігрових моментах A, B, C, D, E, F та комбінацій цих рішень». Завдання, як бачиш, минулі десятиліття явно ускладнабося. Отже, ускладнабося і типи даних. Це ще одна причина виникнення ОВП. Приклад із рівнянням легко можна вирішити за допомогою звичайних примітивів, жодних об'єктів тут не треба. А ось завдання з кінцівками гри складно буде навіть описати, не використовуючи якихось придуманих тобою класів. Але при цьому описати її в класах та об'єктах досить легко: нам явно буде потрібен клас Гра, клас Сталкер, клас Кінцівка, клас РішенняГравця, клас Ігровий Момент і так далі. Тобто навіть не приступивши до розв'язання задачі, ми в голові можемо легко уявити «малюнки» її розв'язання. Ускладнення завдань поставило програмістів перед необхідністю ділити завдання частини. Але у процедурному програмуванні зробити це було не так просто. І дуже часто програма була «дерево» з купи гілок з усіма можливими варіантами її роботи. Залежно від якихось умов, програма виконувалася за тією чи іншою гілкою. Для невеликих програм такий варіант був зручний, але поділити на частини об'ємне завдання було дуже складно. Ця потреба стала ще однією причиною виникнення ОВП. Ця концепція надала програмістам можливість ділити програму на купу «модулів»-класів, кожен із яких робить свою частину роботи. Усі об'єкти, взаємодіючи між собою, утворюють роботу нашої програми. Крім того, написаний нами код можна повторно використовувати в іншому місці програми, що також заощаджує багато часу.
Коментарі
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
Для цієї сторінки немає коментарів.