Какие знаешь инструменты Dart для ООП?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь инструменты 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
- Используйте абстрактные классы для определения контрактов
- Предпочитайте композицию наследованию — более гибко
- Правильно используйте миксины — для переиспользования поведения
- Соблюдайте SOLID принципы — особенно Single Responsibility
- Используйте обобщения для типизированного кода
- Инкапсулируйте данные — используйте приватные методы и getter/setter
Dart предоставляет мощный и гибкий инструментарий для ООП, позволяющий писать чистый, тестируемый и масштабируемый код.