← Назад к вопросам

Что такое абстрактный класс?

1.3 Junior🔥 121 комментариев
#ООП и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Абстрактный класс в Dart

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

Основные характеристики

Абстрактный класс:

  • Объявляется с ключевым словом abstract
  • Не может быть создан объект напрямую (new AbstractClass() — ошибка)
  • Может содержать абстрактные методы (без реализации)
  • Может содержать обычные методы с реализацией
  • Может содержать переменные и конструкторы
  • Используется для наследования

Синтаксис

// Определение абстрактного класса
abstract class Animal {
  // Абстрактный метод (без реализации)
  void makeSound();
  
  // Обычный метод с реализацией
  void sleep() {
    print('Zzz...');
  }
  
  // Переменная
  String name;
  
  // Конструктор
  Animal({required this.name});
}

// Класс-наследник должен реализовать все абстрактные методы
class Dog extends Animal {
  Dog({required String name}) : super(name: name);
  
  @override
  void makeSound() {
    print('Woof!');
  }
}

class Cat extends Animal {
  Cat({required String name}) : super(name: name);
  
  @override
  void makeSound() {
    print('Meow!');
  }
}

void main() {
  // ❌ Нельзя инстанцировать абстрактный класс
  // var animal = Animal(name: 'Generic'); // Ошибка!
  
  // ✅ Инстанцируем наследников
  var dog = Dog(name: 'Rex');
  var cat = Cat(name: 'Whiskers');
  
  dog.makeSound();  // Выведет: Woof!
  cat.makeSound();  // Выведет: Meow!
  
  dog.sleep();      // Выведет: Zzz...
  cat.sleep();      // Выведет: Zzz...
}

Абстрактные методы

Абстрактный метод — это метод без реализации. Каждый класс-наследник обязан его реализовать.

abstract class Shape {
  // Абстрактный метод — только сигнатура
  double calculateArea();
  
  // Абстрактный метод с параметрами
  void draw(Canvas canvas);
  
  // Метод с реализацией (опционально переопределять)
  void printInfo() {
    print('This is a shape');
  }
}

class Circle extends Shape {
  double radius;
  
  Circle({required this.radius});
  
  @override
  double calculateArea() {
    return 3.14 * radius * radius;
  }
  
  @override
  void draw(Canvas canvas) {
    // Рисовать круг
  }
}

class Rectangle extends Shape {
  double width, height;
  
  Rectangle({required this.width, required this.height});
  
  @override
  double calculateArea() {
    return width * height;
  }
  
  @override
  void draw(Canvas canvas) {
    // Рисовать прямоугольник
  }
}

Абстрактный класс с полной реализацией

Абстрактный класс может содержать методы с полной реализацией:

abstract class Vehicle {
  String brand;
  
  Vehicle({required this.brand});
  
  // Абстрактный метод
  void drive();
  
  // Конкретный метод
  void honk() {
    print('$brand: Honk honk!');
  }
  
  void showBrand() {
    print('Brand: $brand');
  }
}

class Car extends Vehicle {
  Car({required String brand}) : super(brand: brand);
  
  @override
  void drive() {
    print('$brand car is driving on road');
  }
}

class Boat extends Vehicle {
  Boat({required String brand}) : super(brand: brand);
  
  @override
  void drive() {
    print('$brand boat is sailing on water');
  }
}

void main() {
  var car = Car(brand: 'Toyota');
  var boat = Boat(brand: 'Yamaha');
  
  car.drive();        // Toyota car is driving on road
  car.honk();         // Toyota: Honk honk!
  car.showBrand();    // Brand: Toyota
  
  boat.drive();       // Yamaha boat is sailing on water
  boat.honk();        // Yamaha: Honk honk!
}

Различие с interface

В Dart нет отдельного ключевого слова interface. Вместо этого используются классы (обычно абстрактные) или abstract class.

Абстрактный класс vs обычный класс:

// Абстрактный класс
abstract class Logger {
  void log(String message); // Абстрактный метод
  void info(String msg) {
    log('[INFO] $msg');
  }
}

// Реализация
class ConsoleLogger extends Logger {
  @override
  void log(String message) {
    print(message);
  }
}

// Использование как интерфейс
class MyApp {
  final Logger _logger;
  
  MyApp(this._logger);
  
  void run() {
    _logger.info('App started');
  }
}

void main() {
  var logger = ConsoleLogger();
  var app = MyApp(logger);
  app.run(); // App started
}

Абстрактный класс с конструктором

abstract class DatabaseConnection {
  String connectionString;
  bool isConnected = false;
  
  // Конструктор для инициализации
  DatabaseConnection({required this.connectionString});
  
  // Абстрактные методы
  Future<void> connect();
  Future<void> disconnect();
  Future<List<Map>> query(String sql);
  
  // Конкретный метод
  void printStatus() {
    print('Connected: $isConnected to $connectionString');
  }
}

class PostgreSQLConnection extends DatabaseConnection {
  PostgreSQLConnection({required String connectionString})
      : super(connectionString: connectionString);
  
  @override
  Future<void> connect() async {
    print('Connecting to PostgreSQL...');
    await Future.delayed(Duration(milliseconds: 500));
    isConnected = true;
  }
  
  @override
  Future<void> disconnect() async {
    isConnected = false;
  }
  
  @override
  Future<List<Map>> query(String sql) async {
    return [{"id": 1, "name": "John"}];
  }
}

Практический пример: Archicture паттерн

// Domain Layer
abstract class UserRepository {
  Future<User> getUserById(String id);
  Future<void> saveUser(User user);
  Future<void> deleteUser(String id);
}

// Infrastructure Layer
class UserRepositoryImpl implements UserRepository {
  final ApiClient _apiClient;
  
  UserRepositoryImpl(this._apiClient);
  
  @override
  Future<User> getUserById(String id) async {
    final response = await _apiClient.get('/users/$id');
    return User.fromJson(response);
  }
  
  @override
  Future<void> saveUser(User user) async {
    await _apiClient.post('/users', user.toJson());
  }
  
  @override
  Future<void> deleteUser(String id) async {
    await _apiClient.delete('/users/$id');
  }
}

// Application Layer
class GetUserUseCase {
  final UserRepository _repository;
  
  GetUserUseCase(this._repository);
  
  Future<User> call(String id) => _repository.getUserById(id);
}

void main() async {
  final apiClient = ApiClient();
  final repository = UserRepositoryImpl(apiClient);
  final useCase = GetUserUseCase(repository);
  
  final user = await useCase('123');
  print(user.name);
}

Преимущества абстрактных классов

1. Контрактность — определяет, что должны реализовать наследники

2. Полиморфизм — можно использовать ссылку на абстрактный класс

List<Shape> shapes = [
  Circle(radius: 5),
  Rectangle(width: 10, height: 20),
];

for (var shape in shapes) {
  print(shape.calculateArea()); // Полиморфизм
}

3. Code reusability — общий код в абстрактном классе

4. Design contracts — явно указывает, какие методы должны быть реализованы

5. Чистая архитектура — разделение слоёв (domain определяет interface, infrastructure реализует)

Вывод

Абстрактный класс — это мощный инструмент для проектирования архитектуры. Используется для определения контрактов, достижения полиморфизма и следования принципу DIP (Dependency Inversion Principle) из SOLID.