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

Какие знаешь инструменты Dart для ООП?

1.0 Junior🔥 131 комментариев
#Dart#ООП и паттерны

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

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

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

Какие знаешь инструменты Dart для ООП?

Dart имеет богатый набор инструментов для объектно-ориентированного программирования, которые позволяют писать гибкий, тестируемый и переиспользуемый код. Рассмотрю основные и продвинутые возможности.

Основные концепции ООП

Классы и объекты:

class User {
  final String id;
  final String name;
  int age;
  
  User({required this.id, required this.name, this.age = 0});
  
  void printInfo() => print('User: $name');
}

final user = User(id: '1', name: 'John', age: 30);
user.printInfo();

Наследование:

class Person {
  final String name;
  
  Person(this.name);
  
  void greet() => print('Hello, I am $name');
}

class Student extends Person {
  final String studentId;
  
  Student({required String name, required this.studentId}) : super(name);
  
  @override
  void greet() {
    super.greet();
    print('My student ID is $studentId');
  }
}

Интерфейсы (Interfaces)

В Dart интерфейс — это контракт, который класс должен выполнить. Любой класс может быть интерфейсом:

abstract class DataSource {
  Future<List<User>> fetchUsers();
}

class ApiDataSource implements DataSource {
  @override
  Future<List<User>> fetchUsers() async {
    // Реализация через API
    return [];
  }
}

class LocalDataSource implements DataSource {
  @override
  Future<List<User>> fetchUsers() async {
    // Реализация через локальное хранилище
    return [];
  }
}

Абстрактные классы (Abstract Classes)

Отличаются от интерфейсов тем, что могут содержать реализацию:

abstract class Animal {
  String get name; // Абстрактное свойство
  
  void makeSound(); // Абстрактный метод
  
  void sleep() { // Конкретная реализация
    print('$name is sleeping');
  }
}

class Dog extends Animal {
  @override
  String get name => 'Dog';
  
  @override
  void makeSound() => print('Woof!');
}

Миксины (Mixins)

Позволяют переиспользовать код между независимыми классами:

mixin Loggable {
  void log(String message) => print('[LOG] $message');
}

mixin Serializable {
  Map<String, dynamic> toJson();
}

class User with Loggable, Serializable {
  final String name;
  
  User(this.name);
  
  @override
  Map<String, dynamic> toJson() => {'name': name};
}

final user = User('John');
user.log('User created'); // Из миксина Loggable

Порядок выполнения при применении нескольких миксинов (MRO):

mixin A {
  void sayA() => print('A');
}

mixin B {
  void sayB() => print('B');
}

class C with A, B {}

final c = C();
c.sayA(); // A
c.sayB(); // B

Полиморфизм (Polymorphism)

Переопределение методов:

abstract class Shape {
  double area();
}

class Circle extends Shape {
  final double radius;
  
  Circle(this.radius);
  
  @override
  double area() => 3.14 * radius * radius;
}

class Rectangle extends Shape {
  final double width, height;
  
  Rectangle(this.width, this.height);
  
  @override
  double area() => width * height;
}

void printArea(Shape shape) => print('Area: ${shape.area()}');

printArea(Circle(5)); // Работает
printArea(Rectangle(4, 6)); // Тоже работает (полиморфизм)

Обобщения (Generics)

Позволяют создавать переиспользуемый типизированный код:

class Repository<T> {
  final List<T> _cache = [];
  
  void add(T item) => _cache.add(item);
  
  List<T> getAll() => _cache;
  
  T? findById(int id) => _cache.isNotEmpty ? _cache[id] : null;
}

class User {
  final String id;
  final String name;
  
  User(this.id, this.name);
}

final userRepo = Repository<User>();
userRepo.add(User('1', 'John'));
final users = userRepo.getAll(); // List<User>

Ограничения типов (Constraints):

class Database<T extends DataModel> {
  Future<void> save(T item) async {
    // Гарантируем, что T имеет методы DataModel
    await item.validate();
  }
}

abstract class DataModel {
  Future<void> validate();
}

Инкапсуляция (Encapsulation)

Dart использует подчеркивание для приватности:

class BankAccount {
  double _balance = 0; // Приватное свойство
  
  double get balance => _balance; // Getter
  
  set balance(double amount) { // Setter
    if (amount < 0) throw ArgumentError('Amount must be positive');
    _balance = amount;
  }
  
  void _logTransaction(String type) { // Приватный метод
    print('[$type] Balance: $_balance');
  }
}

final account = BankAccount();
account.balance = 1000; // Setter
print(account.balance); // Getter
// account._balance = -100; // Ошибка! Приватное

Перегрузка операторов (Operator Overloading)

class Vector {
  final double x, y;
  
  Vector(this.x, this.y);
  
  Vector operator +(Vector other) {
    return Vector(x + other.x, y + other.y);
  }
  
  Vector operator *(double scalar) {
    return Vector(x * scalar, y * scalar);
  }
  
  @override
  bool operator ==(Object other) {
    if (other is! Vector) return false;
    return x == other.x && y == other.y;
  }
  
  @override
  int get hashCode => x.hashCode ^ y.hashCode;
}

final v1 = Vector(1, 2);
final v2 = Vector(3, 4);
final v3 = v1 + v2; // Vector(4, 6)
final v4 = v1 * 2; // Vector(2, 4)
print(v1 == Vector(1, 2)); // true

Extension методы

Добавляют функционал к существующим классам:

extension StringExtension on String {
  bool get isEmailValid => contains('@');
  
  String get capitalize => this[0].toUpperCase() + substring(1);
  
  String repeat(int times) => List.filled(times, this).join('');
}

final email = 'user@example.com';
print(email.isEmailValid); // true
print('hello'.capitalize); // Hello
print('ha'.repeat(3)); // hahaha

Перечисления (Enums) с методами

enum Status {
  pending('Ожидание'),
  active('Активен'),
  inactive('Неактивен'),
  deleted('Удалён');
  
  final String label;
  
  const Status(this.label);
  
  bool get isActive => this == Status.active;
  
  String get emoji => switch(this) {
    Status.pending => '⏳',
    Status.active => '✅',
    Status.inactive => '⏹️',
    Status.deleted => '🗑️',
  };
}

print(Status.active.label); // Активен
print(Status.active.emoji); // ✅

Sealed классы (Dart 3.0+)

Ограничивают иерархию наследования:

sealed class Result {}

class Success extends Result {
  final String message;
  Success(this.message);
}

class Error extends Result {
  final String error;
  Error(this.error);
}

String processResult(Result result) => switch(result) {
  Success(message: var msg) => 'Success: $msg',
  Error(error: var err) => 'Error: $err',
};

Статические члены класса

class Counter {
  static int _count = 0;
  static const int MAX_COUNT = 100;
  
  static void increment() => _count++;
  
  static int get count => _count;
  
  static void reset() => _count = 0;
}

Counter.increment();
print(Counter.count); // 1
print(Counter.MAX_COUNT); // 100

Лучшие практики ООП в Dart

  1. Используйте абстрактные классы для определения контрактов
  2. Предпочитайте композицию наследованию — более гибко
  3. Правильно используйте миксины — для переиспользования поведения
  4. Соблюдайте SOLID принципы — особенно Single Responsibility
  5. Используйте обобщения для типизированного кода
  6. Инкапсулируйте данные — используйте приватные методы и getter/setter

Dart предоставляет мощный и гибкий инструментарий для ООП, позволяющий писать чистый, тестируемый и масштабируемый код.