Зображення: freepik
Перед тим, як перейти до більш складних прикладів абстракції (abstract class та Interface), давайте спершу розглянемо базову версію, наступні 2 частини цієї короткої серії будуть складнішими, оскільки ми знову перейдемо до платіжних систем.
Що таке абстракція?
Розглядайте абстракцію як мистецтво приховування непотрібних деталей, показуючи лише найважливіше. Це як водіння автомобіля: вам не потрібно знати, як працює двигун, але ви знаєте, що натискання на акселератор змушує його ричати.
В програмуванні абстракція дозволяє зосередитися на чому робить об'єкт, а не як він це робить.
Може виникнути деяка плутанина з інкапсуляцією, оскільки спочатку мені було складно розрізнити їх, але давайте прояснимо це:
- Інкапсуляція приховує дані (обмежує прямий доступ).
- Абстракція приховує реалізацію.
Обидва ці принципи спрямовані на те, щоб показати лише те, що необхідно, але інкапсуляція більше стосується захисту внутрішніх станів, а абстракція – спрощення використання. Чи стало це зрозуміліше? 😊
Ось текстове уявлення для візуалізації взаємозв'язку між класами, підкласами, абстрактними класами та їх підкласами:
Звичайний клас та підкласи
Class: Animal
+---------------------+
| Animal |
|---------------------|
| - name: String | <-- Атрибути (приватні змінні)
| - age: int |
|---------------------|
| + eat(): void | <-- Методи (публічні поведінки)
| + speak(): void |
+---------------------+
| (Наслідування)
v
Subclass: Dog
+---------------------+
| Dog |
|---------------------|
| + speak(): void | <-- Реалізація методу speak
+---------------------+
| (Наслідування)
v
Subclass: Cat
+---------------------+
| Cat |
|---------------------|
| + speak(): void | <-- Реалізація методу speak
+---------------------+
Абстрактний клас і підкласи
Abstract Class: Animal
+---------------------+
| Animal |
|---------------------|
| + speak(): void | <-- Абстрактний метод (без реалізації)
|---------------------|
| + eat(): void | <-- Конкретний метод (спільна реалізація)
+---------------------+
| (Наслідування)
v
Subclass: Dog
+---------------------+
| Dog |
|---------------------|
| + speak(): void | <-- Реалізація абстрактного методу
+---------------------+
| (Наслідування)
v
Subclass: Cat
+---------------------+
| Cat |
|---------------------|
| + speak(): void | <-- Реалізація абстрактного методу
+---------------------+
Ключові примітки:
- Звичайний клас: Може бути інстанційований безпосередньо (наприклад,
Dog dog = new Dog();
). - Абстрактний клас: Не може бути інстанційований безпосередньо. Його підкласи повинні реалізувати всі абстрактні методи, якщо вони не є абстрактними самі по собі.
- Підкласи: Наслідують атрибути та методи від свого батьківського класу, але також можуть мати свої власні унікальні атрибути та поведінку.
Приклад коду
Припустимо, ми створюємо систему зоопарку. Ось абстрактний приклад:
abstract class Animal {
abstract void speak(); // Без реалізації - це абстрактно!
void eat() { // Конкретний метод - всі тварини їдять.
System.out.println("Ця тварина їсть їжу.");
}
}
Тут клас Animal
надає загальний шаблон для всіх тварин. Він каже: «Підкласи, ви повинні визначити метод speak()
, але я оброблю логіку eat()
для вас.»
Абстрактні класи: Керований шаблон
Абстрактний клас – це як напівготова будівля. Вона має основну структуру, але залишає місце для налаштувань. Ви можете змішувати абстрактні методи (чисті ідеї) з конкретними методами (реальними реалізаціями).
Приклад
abstract class Animal {
abstract void speak(); // Повинен бути реалізований підкласами.
void eat() { // Спільна реалізація для всіх тварин.
System.out.println("Ця тварина їсть їжу.");
}
}
System.out.println("Ця тварина їсть їжу.");
}
}
class Dog extends Animal {
void speak() {
System.out.println("Гав!");
}
}
class Cat extends Animal {
void speak() {
System.out.println("Мяу!");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.speak(); // Вивід: Гав!
dog.eat(); // Вивід: Ця тварина їсть їжу.
Animal cat = new Cat();
cat.speak(); // Вивід: Мяу!
}
}
Тут Dog
і Cat
реалізують свої версії методу speak()
, одночасно використовуючи метод eat()
з класу Animal
.
Інтерфейс: Абсолютний контракт
Тепер давайте піднімемо рівень. Що, якщо ми хочемо, щоб непов'язані класи дотримувалися одних і тих же правил? Ось тут вступає інтерфейс, інструмент 100% абстракції. Це як контракт: "Якщо ти мене реалізуєш, ти повинен надавати ці методи."
Приклад
interface Animal {
void speak(); // Без реалізації тут - просто контракт!
}
class Dog implements Animal {
public void speak() {
System.out.println("Гав!");
}
}
class Cat implements Animal {
public void speak() {
System.out.println("Мяу!");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.speak(); // Вивід: Гав!
Animal cat = new Cat();
cat.speak(); // Вивід: Мяу!
}
}
Зверніть увагу на відмінності:
Animal
тепер є інтерфейсом, а не класом.- Ми змушуємо виконання контракту
speak()
, але не залишаємо місця для спільної логіки, якeat()
.
Абстракція vs Абстрактний клас vs Інтерфейс
Ось розбір у чистому, структурованому форматі для легшого розуміння:
1. Визначення
- Абстракція: Приховування непотрібних деталей і надання лише основних функцій.
- Абстрактний клас: Напівготовий клас, який може містити як реалізовані (конкретні) методи, так і нереалізовані (абстрактні) методи.
- Інтерфейс: Повністю абстрактний контракт, який визначає методи, які клас повинен реалізувати.
2. Реалізація
- Абстракція: Це концепція, не прив'язана до конкретного коду.
- Абстрактний клас: Може містити змішування абстрактних методів (без реалізації) та конкретних методів (з реалізацією).
- Інтерфейс: Тільки абстрактні методи, що робить його чистою абстракцією.
3. Поля/Властивості
- Абстракція: Не застосовується безпосередньо до полів чи властивостей.
- Абстрактний клас: Може мати змінні екземплярів і константи.
- Інтерфейс: Тільки константи (за замовчуванням статичні та фінальні).
4. Множинне наслідування
- Абстракція: Не є прямою особливістю, але принцип може працювати між кількома сутностями.
- Абстрактний клас: Не підтримується в Java; клас може успадковувати тільки один абстрактний клас.
- Інтерфейс: Підтримується в Java через множинні інтерфейси.
5. Використання
- Абстракція: Загальний принцип ООП для спрощення та модульності коду.
- Абстрактний клас: Використовується для спільного функціоналу серед пов'язаних класів, з деякими методами, що залишаються для визначення підкласами.
- Інтерфейс: Використовується для забезпечення контракту серед непов'язаних класів або коли потрібне множинне наслідування.
Коли що використовувати?
- Абстракція: Основна концепція для проектування чистих, модульних систем.
- Абстрактний клас: Використовуйте його, коли є спільний функціонал для подібних класів. Розглядайте його як основу для групи схожих об'єктів.
- Інтерфейс: Використовуйте, коли потрібно, щоб абсолютно непов'язані класи поділяли спільний контракт, або коли потрібно множинне наслідування.
Підсумок
- Абстракція – це мета: спростити ваш код і зробити його більш модульним.
- Абстрактні класи – інструмент для часткової абстракції, який дозволяє ділитися логікою з деякими методами, які залишаються для підкласів, абстрактний клас extends.
3.
Інтерфейси є інструментом для чистої абстракції, забезпечуючи суворий "контракт" для кожного класу, який їх реалізує.
ПІДКАЗКА: Коли ви створюєте клас, наприклад, public class baseZoo, замініть public на abstract, і тепер це абстрактний клас, який буде виглядати як abstract class baseZoo, тепер ви можете додавати в нього не реалізовані методи.
Перевірити та завантажити код можна тут
.
.
.
Щасливого кодування!
Перекладено з: Chapter[15]: Abstraction, Abstract Class, and Interface: The OOP Trio Explained: Part 1