Ответ
Абстрактный класс следует выбирать, когда необходимо:
- Предоставить общую реализацию (код) для группы тесно связанных классов. Абстрактный класс может содержать поля, конструкторы и реализованные методы, которые будут унаследованы.
- Объявить нестатические и нефинальные поля, чтобы подклассы могли иметь и модифицировать общее состояние.
- Определить общий шаблон (template method), где часть алгоритма фиксирована, а часть делегирована абстрактным методам подклассов.
Ключевое отличие от интерфейса (до Java 8): абстрактный класс описывает «is-a» отношение (наследование), а интерфейс — «capable-of» (реализация контракта). С появлением default-методов границы размылись, но абстрактный класс по-прежнему необходим для общего состояния.
Пример:
abstract class DataExporter {
protected String dataSource;
public DataExporter(String source) {
this.dataSource = source;
}
// Общая реализация для всех экспортёров
public final void export() {
String data = fetchData();
String formatted = format(data);
save(formatted);
}
protected abstract String fetchData();
protected abstract String format(String rawData);
private void save(String data) {
System.out.println("Saving: " + data);
}
}
class CsvExporter extends DataExporter {
public CsvExporter(String source) { super(source); }
@Override
protected String fetchData() { return "data from " + dataSource; }
@Override
protected String format(String rawData) {
return rawData + " formatted as CSV";
}
}