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

В простейшем случае объект можно представить как набор связанных данных:
void main() {
  var person = {
    'name': 'John',
    'age': 30,
    'city': 'New York',
  };
 
  print(person); // {name: John, age: 30, city: New York}
}Это создает объект с помощью литерала карты (Map) с тремя свойствами: name, age и city. Однако такой подход имеет ограничения. Для создания более сложных объектов с собственным поведением мы используем классы.
Класс — это шаблон (или чертеж), определяющий структуру и поведение объектов определенного типа. Давайте создадим простой класс Article, представляющий статью:
class Article {
  // Поля (свойства) класса
  String title;
  String content;
  String image;
  DateTime publishDate;
  String? author; // Необязательное поле (может быть null)
 
  // Конструктор
  Article(this.title, this.content, this.image) {
    // Инициализируем дату публикации текущим временем
    this.publishDate = DateTime.now();
  }
}Здесь класс Article имеет:
title, content, image и publishDateauthor (с типом String?, что означает, что оно может быть null)Теперь, когда у нас есть класс, мы можем создавать экземпляры этого класса (объекты):
void main() {
  // Создаем объект статьи
  var article = Article(
    'Введение в Dart',
    'Dart — это язык программирования, оптимизированный для приложений. Он разработан Google и используется для создания мобильных, настольных, серверных и веб-приложений.',
    'dart_logo.jpg',
  );
 
  // Доступ к полям объекта
  print('Название: ${article.title}');
  print('Дата публикации: ${article.publishDate}');
  print('Изображение: ${article.image}');
}
Объекты могут не только хранить данные, но и выполнять действия через методы. Давайте расширим наш класс Article полезными методами:
class Article {
  // Поля (свойства) класса
  String title;
  String content;
  String image;
  DateTime publishDate;
  String? author;
 
  // Конструктор с сокращенной записью параметров
  Article(this.title, this.content, this.image) {
    this.publishDate = DateTime.now();
  }
 
  // Геттер для подсчета слов
  int get wordCount {
    return content.split(' ').length;
  }
 
  // Метод для получения краткой информации о статье
  String getSummary() {
    String authorInfo = author != null ? ", автор: $author" : "";
    return '$title - $wordCount слов, опубликовано ${publishDate.day}.${publishDate.month}.${publishDate.year}$authorInfo';
  }
 
  // Сеттер для установки автора
  set authorName(String name) {
    author = name;
  }
}В этом обновленном классе:
wordCount, который подсчитывает количество слов в контенте статьиgetSummary() возвращает краткую информацию о статьеauthorName позволяет установить имя автора статьиvoid main() {
  var article = Article(
    'Основы объектов в Dart',
    'Объектно-ориентированное программирование — это подход к программированию, основанный на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса.',
    'oop.jpg',
  );
 
  // Устанавливаем автора с помощью сеттера
  article.authorName = 'Иван Петров';
 
  // Выводим информацию о статье
  print(article.getSummary());
  print('Количество слов: ${article.wordCount}');
}
Объекты могут взаимодействовать друг с другом, образуя более сложные системы. Давайте создадим класс Author и покажем, как он может взаимодействовать с классом Article:
class Author {
  String name;
  String email;
  DateTime registrationDate;
  List<Article> articles = []; // Список статей автора
 
  // Сокращенный синтаксис конструктора
  Author(this.name, this.email, this.registrationDate);
 
  // Метод для добавления статьи
  void addArticle(Article article) {
    // Устанавливаем автора статьи
    article.authorName = this.name;
    // Добавляем статью в список
    articles.add(article);
  }
 
  // Метод для получения общего количества слов во всех статьях
  int getTotalWordCount() {
    int total = 0;
    for (var article in articles) {
      total += article.wordCount;
    }
    return total;
  }
 
  // Получить информацию об авторе
  String getInfo() {
    return '$name ($email) - ${articles.length} статей';
  }
}void main() {
  // Создаем автора
  var author = Author(
    'Иван Петров',
    'ivan@example.com',
    DateTime(2023, 5, 10),
  );
 
  // Создаем несколько статей
  var article1 = Article(
    'Введение в Dart',
    'Dart — это язык программирования, разработанный Google для создания масштабируемых веб-приложений, мобильных приложений и приложений для Интернета вещей.',
    'dart.jpg',
  );
 
  var article2 = Article(
    'Объекты в Dart',
    'В Dart все является объектом, включая числа, функции и даже null. Все объекты наследуются от класса Object.',
    'objects.jpg',
  );
 
  // Добавляем статьи автору
  author.addArticle(article1);
  author.addArticle(article2);
 
  // Выводим информацию
  print(author.getInfo());
  print('Общее количество слов: ${author.getTotalWordCount()}');
 
  // Выводим информацию о статьях
  for (var article in author.articles) {
    print(article.getSummary());
  }
}
Теперь давайте объединим наши знания для создания простой блог-системы:
class Blog {
  String name;
  List<Author> authors = [];
 
  Blog(this.name);
 
  void addAuthor(Author author) {
    authors.add(author);
  }
 
  List<Article> getAllArticles() {
    List<Article> allArticles = [];
    for (var author in authors) {
      allArticles.addAll(author.articles);
    }
    return allArticles;
  }
 
  void printSummary() {
    print('=== БЛОГ: $name ===');
    print('Авторов: ${authors.length}');
    print('Статей: ${getAllArticles().length}');
 
    print('\nАвторы:');
    for (var author in authors) {
      print('- ${author.getInfo()}');
    }
 
    print('\nСтатьи:');
    for (var article in getAllArticles()) {
      print('- ${article.getSummary()}');
    }
  }
}
 
void main() {
  // Создаем блог
  var blog = Blog('TechBlog');
 
  // Создаем авторов
  var author1 = Author('Анна Иванова', 'anna@blog.com', DateTime(2023, 3, 15));
  var author2 = Author('Петр Сидоров', 'petr@blog.com', DateTime(2023, 7, 22));
 
  // Создаем статьи
  var article1 = Article(
    'Особенности Dart',
    'Dart — современный язык программирования с поддержкой сильной типизации, null safety и асинхронного программирования.',
    'dart_logo.png',
  );
 
  var article2 = Article(
    'Путешествие по Европе',
    'Европа предлагает богатую историю, разнообразную культуру и впечатляющую архитектуру.',
    'europe.jpg',
  );
 
  var article3 = Article(
    'Лучшие рецепты итальянской кухни',
    'Итальянская кухня славится своими пастой, пиццей и тирамису.',
    'italian_food.jpg',
  );
 
  // Добавляем статьи авторам
  author1.addArticle(article1);
  author1.addArticle(article3);
  author2.addArticle(article2);
 
  // Добавляем авторов в блог
  blog.addAuthor(author1);
  blog.addAuthor(author2);
 
  // Выводим информацию о блоге
  blog.printSummary();
}
При работе с объектами в Dart важно понимать следующие ключевые принципы ООП:
Инкапсуляция — объединение данных и методов, которые работают с этими данными, в одной "капсуле" (классе). Это позволяет скрыть детали реализации и предоставить только необходимый интерфейс.
Наследование — механизм, позволяющий создавать новые классы на основе существующих. Например, класс VideoArticle может наследовать свойства и методы класса Article и добавлять свои специфичные функции.
Полиморфизм — способность объектов с одинаковым интерфейсом иметь различные реализации. Например, методы getSummary() могут по-разному работать в разных подклассах Article.
Абстракция — выделение наиболее важных характеристик объекта и игнорирование несущественных. Например, при моделировании автора нас интересуют его имя и статьи, но не его рост или вес.
Объекты в Dart позволяют организовать код в логические структуры, объединяющие данные и поведение. В этой статье мы рассмотрели:
Объектно-ориентированное программирование значительно упрощает разработку, делая код более организованным, понятным и поддерживаемым. По мере усложнения программ преимущества этого подхода становятся все более очевидными.
К сожалению, при объяснении объектов и классов мы используем термины и инструменты, которые сами требуют объяснения. Невозможно охватить все аспекты ООП в одной статье. Каждая следующая статья будет отвечать на один вопрос и, возможно, задавать два новых.
Чтобы действительно освоить Dart и ООП, необходимо:
Задачи для закрепления навыков объектно-ориентированного программирования
Задача: Создать класс Swan (Лебедь) с атрибутами и методами. Создать несколько экземпляров с разными характеристиками.
// Пример кода для начала:
class Swan {
  String name;
  String color;
  double wingspan;
  int age;
 
  // Добавьте конструктор и методы
}
 
// Создайте несколько экземпляров с различными атрибутамиЗадача: Создать класс Book с различными атрибутами и методами. Создать 5 экземпляров этого класса.
// Пример кода для начала:
class Book {
  String title;
  String isbn;
  String author;
  int publicationYear;
  int pageCount;
  String bindingType;
  String genre;
  double rating;
  double price;
 
  // Добавьте конструктор и методы
}
 
// Создайте экземпляры: азбука, война и мир, книга о вкусной и полезной пище и два по вашему выборуЗадача: Создать класс BankAccount, который моделирует работу банковского счета с операциями пополнения, снятия и проверки баланса.
class BankAccount {
  // Добавьте необходимые атрибуты
 
  // Реализуйте конструктор
 
  // Метод deposit для внесения средств
 
  // Метод withdraw для снятия средств
 
  // Метод getBalance для проверки баланса
 
  // Метод toString для вывода информации о счете
}
 
// Создайте несколько счетов и выполните операции с нимиЗадача: Создать класс Car, который моделирует автомобиль с возможностью запуска двигателя, движения, торможения и отображения текущего состояния.
class Car {
  // Добавьте необходимые атрибуты (марка, модель, год выпуска, цвет и т.д.)
 
  // Добавьте атрибуты для хранения состояния (запущен двигатель или нет, текущая скорость)
 
  // Реализуйте конструктор
 
  // Метод для запуска двигателя
 
  // Метод для остановки двигателя
 
  // Метод для ускорения
 
  // Метод для торможения
 
  // Метод для отображения текущего состояния
}
 
// Создайте несколько автомобилей и продемонстрируйте их использованиеЗадача: Создать класс Student и класс Course. Студент может быть зарегистрирован на нескольких курсах, а курс может содержать нескольких студентов.
class Student {
  // Атрибуты (имя, возраст, идентификатор и т.д.)
 
  // Список курсов, на которые зарегистрирован студент
 
  // Реализуйте конструктор
 
  // Метод для регистрации на курс
 
  // Метод для отмены регистрации
 
  // Метод для отображения списка курсов
}
 
class Course {
  // Атрибуты (название, код, преподаватель и т.д.)
 
  // Список зарегистрированных студентов
 
  // Реализуйте конструктор
 
  // Метод для добавления студента
 
  // Метод для удаления студента
 
  // Метод для отображения списка студентов
}
 
// Создайте несколько студентов и курсов, зарегистрируйте студентов на курсыЗадача: Создать класс Product и класс Inventory для управления складом продуктов.
class Product {
  // Атрибуты (название, цена, количество, категория и т.д.)
 
  // Реализуйте конструктор
 
  // Геттеры и сеттеры при необходимости
 
  // Метод для обновления информации о продукте
}
 
class Inventory {
  // Список продуктов
 
  // Реализуйте конструктор
 
  // Метод для добавления продукта
 
  // Метод для удаления продукта
 
  // Метод для поиска продукта по названию или категории
 
  // Метод для отображения всего инвентаря
}
 
// Создайте инвентарь и добавьте несколько продуктовЗадача: Создать класс Note и класс NoteApp для управления заметками.
class Note {
  // Атрибуты (заголовок, содержание, дата создания, теги и т.д.)
 
  // Реализуйте конструктор
 
  // Геттеры и сеттеры при необходимости
 
  // Метод для редактирования заметки
 
  // Метод для отображения заметки
}
 
class NoteApp {
  // Список заметок
 
  // Реализуйте конструктор
 
  // Метод для создания новой заметки
 
  // Метод для удаления заметки
 
  // Метод для поиска заметок по заголовку или тегам
 
  // Метод для отображения всех заметок
}
 
// Создайте приложение для заметок и добавьте несколько заметок