Ответ
Выбор между абстрактным классом и интерфейсом зависит от проектируемой абстракции.
Используйте абстрактный класс, когда:
- Нужно разделить общее состояние (поля) между несколькими родственными классами.
- Требуется реализовать нестатический/нефинальный метод с общей логикой для всех наследников (шаблонный метод).
- Необходим конструктор для инициализации общего состояния.
- Нужны модификаторы доступа
protectedилиpackage-privateдля методов или полей.
Пример абстрактного класса (шаблонный метод):
public abstract class ReportGenerator {
// Общее состояние
protected String reportName;
// Шаблонный метод (определяет скелет алгоритма)
public final void generateReport() {
fetchData();
processData(); // Абстрактный шаг
formatReport(); // Абстрактный шаг
saveReport(); // Общая реализация
}
protected abstract void processData();
protected abstract void formatReport();
private void saveReport() {
System.out.println("Отчет '" + reportName + "' сохранен.");
}
}
Используйте интерфейс, когда:
- Нужно определить контракт (поведение) для несвязанных классов. Классы
CarиPlaneмогут реализовыватьMovable. - Требуется множественное "наследование" типов (класс может реализовать много интерфейсов).
- Хотите добавить функциональность через default-методы (начиная с Java 8), не ломая существующие реализации.
- Создаете API или библиотеку, где реализация скрыта.
Современная практика:
- Предпочитайте интерфейсы для определения типов (с
default-методами для общей логики). - Используйте абстрактные классы реже, только когда действительно необходимо наследование состояния или строгий контроль структуры алгоритма.