Что такое абстрактный класс в Dart и для чего он используется?

«Что такое абстрактный класс в Dart и для чего он используется?» — вопрос из категории ООП, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Dart абстрактный класс — это класс, который нельзя инстанциировать напрямую с помощью конструктора. Он служит шаблоном или контрактом для своих подклассов, определяя общий интерфейс (методы, свойства) и, возможно, часть реализации.

Ключевые характеристики:

  • Объявляется с ключевым словом abstract.
  • Может содержать абстрактные методы (объявлены без тела, с ;).
  • Может содержать конкретные методы (с полной реализацией).
  • Может содержать поля, геттеры, сеттеры и конструкторы (хотя конструктор абстрактного класса можно вызвать только из конструктора подкласса).
  • Класс, наследующий абстрактный класс, должен реализовать (override) все его абстрактные методы, если сам не объявлен абстрактным.

Пример: Моделирование геометрических фигур

abstract class Shape {
  // Абстрактный метод: должен быть реализован в подклассе
  double area(); 

  // Абстрактный геттер
  String get name;

  // Конкретный метод с реализацией, доступный всем подклассам
  void printDescription() {
    print('I am a $name with area: ${area().toStringAsFixed(2)}');
  }
}

class Circle extends Shape {
  final double radius;

  Circle(this.radius);

  @override
  double area() => 3.14159 * radius * radius;

  @override
  String get name => 'Circle';
}

class Rectangle extends Shape {
  final double width;
  final double height;

  Rectangle(this.width, this.height);

  @override
  double area() => width * height;

  @override
  String get name => 'Rectangle';
}

void main() {
  final shapes = <Shape>[
    Circle(5),
    Rectangle(4, 6),
  ];

  for (final shape in shapes) {
    shape.printDescription(); // Полиморфный вызов
    // Вывод:
    // I am a Circle with area: 78.54
    // I am a Rectangle with area: 24.00
  }
}

Сравнение с интерфейсами (implicit interfaces) в Dart: В Dart каждый класс неявно определяет интерфейс. Абстрактный класс, не содержащий конкретных методов, концептуально похож на интерфейс. Однако ключевое отличие в том, что абстрактный класс может содержать реализацию и состояние (поля), а также ограничивать иерархию наследования (класс может наследовать только один абстрактный класс, но реализовать много интерфейсов). Я использую абстрактные классы, когда хочу задать общее поведение и частичную реализацию для группы связанных классов.