В чем разница между абстрактным классом и интерфейсом в Dart?

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

Ответ

В Dart и абстрактные классы, и интерфейсы используются для определения контрактов, но с разной степенью гибкости и реализации.

Абстрактный класс (abstract class)

  • Может содержать как абстрактные методы (без тела), так и реализованные методы, поля, конструкторы.
  • Поддерживает одиночное наследование (класс может extends только один абстрактный класс).
  • Идеален для создания шаблона с частичной готовой реализацией.

    
    abstract class DataRepository {
    // Поле с реализацией
    final String endpoint = '/api/data';
    
    // Абстрактный метод (контракт)
    Future<List<dynamic>> fetchAll();
    
    // Реализованный метод (общая логика)
    void logError(String error) {
    print('Repository error: $error');
    }
    }

class UserRepository extends DataRepository { @override Future<List> fetchAll() { // Обязаны реализовать только fetchAll() // Метод logError() уже унаследован return HttpClient().get(endpoint); } }


### Интерфейс
*   В Dart **любой класс неявно определяет интерфейс**. Ключевого слова `interface` нет.
*   Для реализации интерфейса используется `implements`.
*   Класс может реализовать **несколько** интерфейсов.
*   При реализации **обязан предоставить свою реализацию ВСЕХ** публичных членов этого класса (и методов, и полей).
```dart
// Классы, которые мы используем как интерфейсы
class JsonSerializable {
  String toJson() => ''; // Сигнатура метода
}

class Identifiable {
  final int id;
  Identifiable(this.id); // Даже поле и конструктор должны быть переопределены
}

// Класс реализует два интерфейса
class User implements JsonSerializable, Identifiable {
  @override
  int id; // Поле должно быть объявлено

  @override
  String toJson() => '{"id": $id}'; // Метод должен быть реализован

  // Конструктор также нужно объявить
  User(this.id);
}

Практическое правило в Dart:

  • Используйте abstract class с extends, когда вам нужна общая базовая логика и отношение "является".
  • Используйте implements, когда вам нужна только сигнатура (контракт) или множественное "наследование" поведения.

Видео-ответы