Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка КР.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
185.34 Кб
Скачать

5.2. Абстрактні класи

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

Розглянемо кілька прикладів.

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

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

Але як вчинити з методом рисування? Адже батьківський клас не являє собою яку-небудь фігуру, у нього немає візуального представлення. Можна оголосити метод paint() в кожній компоненті незалежно. Але тоді контейнер повинен володіти складною функціональністю для аналізу того, яка саме компонента зараз обробляється, робити приведення типу і тільки після цього викликати потрібний метод.

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

Аналогічно робимо і в наступному прикладі, де реалізуємо найпростіший калькулятор:

/ / Базова арифметична операція

abstract class Operation {

public abstract int calculate(int a, int b);

}

// Додавання

class Addition {

public int calculate(int a, int b) {

return a+b;

}

}

// Віднімання

class Subtraction {

public int calculate(int a, int b) {

return a-b;

}

}

class Test {

public static void main(String s[]) {

Operation o1 = new Addition();

Operation o2 = new Subtraction();

o1.calculate(2, 3);

o2.calculate(3, 5);

}

}

Видно, що виконання операцій додавання і віднімання в методі main () записуються абсолютно однаковим чином.

Зверніть увагу - оскільки абстрактний метод не має тіла, після опису його заголовка ставиться крапка з комою. А раз у нього немає тіла, то до нього можна звертатися, поки його спадкоємці не опишуть реалізацію. Це означає, що не можна створювати екземпляри класу, у якого є абстрактні методи. Такий клас сам оголошується абстрактним.

Клас може бути абстрактним і в разі, якщо у нього немає абстрактних методів, але повинен бути абстрактним, якщо такі методи є. Розробник може вказати ключове слово abstract в списку модифікаторів класу, якщо хоче заборонити створення екземплярів цього класу. Класи-спадкоємці повинні реалізувати (implements) усі абстрактні методи (якщо вони є) свого абстрактного батька, щоб їх можна було оголошувати не абстрактними і породжувати від них екземпляри.