Классы, объекты и конструкторы

Класс — это чертёж, объект — изделие по нему; так данные и поведение объединяются в одну сущность.

Суть: класс описывает поля (данные) и методы (поведение). Конструктор создаёт объект и заполняет поля. Dart предлагает компактный синтаксис конструкторов, который экономит десятки строк.

У Dart-классов есть приятная мелочь — геттеры и сеттеры, которые выглядят как поля, но за ними стоит вычисление. Например, у класса Rectangle можно объявить double get area => width * height; и обращаться к нему как к свойству: rect.area. Это позволяет прятать логику за простым именем и менять реализацию, не трогая код, который этим свойством пользуется. Геттеры повсюду в исходниках Flutter.

Пока данные лежат в отдельных переменных, легко перепутать, чьё имя и чей возраст. ООП решает это: вы объединяете связанные данные и действия над ними в класс. User хранит имя и возраст и умеет здороваться. Каждый конкретный пользователь — это объект (экземпляр) класса.

class User {
  final String name;
  final int age;

  // конструктор с сокращённым синтаксисом this.
  User(this.name, this.age);

  // метод — поведение объекта
  String greet() => 'Привет, я $name, мне $age';
}

void main() {
  final u = User('Аня', 20);   // создаём объект
  print(u.name);               // Аня
  print(u.greet());            // Привет, я Аня, мне 20
}

Запись User(this.name, this.age) — фирменная краткость Dart. В других языках пришлось бы писать this.name = name; вручную; здесь this. в параметрах сразу присваивает значение полю.

Как работают конструкторы под капотом

Конструктор — это специальный метод, который вызывается при создании объекта и гарантирует, что все обязательные поля заполнены. У класса может быть несколько конструкторов через именованные конструкторы: User.guest(), User.fromJson(...). Это удобно, когда объект можно создать разными способами.

  class User {
    name, age          поля (данные)
    greet()            метод (поведение)
  }
       |
       | User('Аня', 20)        обычный конструктор
       | User.guest()           именованный конструктор
       v
  +----------------+   +----------------+
  | объект: Аня,20 |   | объект: Гость,0|   разные экземпляры
  +----------------+   +----------------+
class User {
  final String name;
  final int age;

  User(this.name, this.age);

  // именованный конструктор
  User.guest() : name = 'Гость', age = 0;

  // именованный конструктор с именованными параметрами
  User.named({required this.name, this.age = 18});
}

final guest = User.guest();
final bob = User.named(name: 'Боря');

Во Flutter каждый виджет — это класс, а его создание — вызов конструктора с именованными параметрами. Поэтому понимание классов и конструкторов напрямую переносится на чтение любого Flutter-кода.

# Аналог класса Dart с обычным и "именованным" конструктором
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def guest(cls):                # аналог именованного конструктора
        return cls('Гость', 0)

    def greet(self):
        return f'Привет, я {self.name}, мне {self.age}'

u = User('Аня', 20)
g = User.guest()
print(u.greet())
print(g.greet())

Частые ошибки

  • Забыть заполнить final-поле в конструкторе — компилятор не позволит создать объект.
  • Писать this.name = name вручную, когда есть краткая форма this.name в параметрах.
  • Путать класс и объект. Класс — чертёж, объект — конкретное изделие, созданное конструктором.

Best practices

  • Делайте поля final, если объект не должен меняться, — это безопаснее и дружит с виджетами.
  • Используйте именованные конструкторы для разных сценариев создания: fromJson, empty, guest.
  • Имена классов — в UpperCamelCase: UserProfile, а не userprofile.

Когда классов в проекте становится много, на первый план выходит инкапсуляция — сокрытие внутренних деталей. В Dart приватность задаётся подчёркиванием в начале имени: поле _counter или класс _HomeState доступны только внутри своего файла. Именно поэтому объекты состояния виджетов принято называть с подчёркивания — они служебные и не должны быть видны снаружи. Привыкайте скрывать всё, что не является частью публичного контракта класса.

Итог: класс объединяет данные и поведение, а конструктор создаёт объекты. Краткий синтаксис this. и именованные конструкторы — это то, что вы увидите в каждом виджете Flutter, ведь виджеты и есть классы.

Проверьте себя
1. Что делает сокращённый синтаксис User(this.name, this.age);?
AСоздаёт две переменные
BАвтоматически присваивает аргументы одноимённым полям
CВызывает метод greet
DДелает поля изменяемыми
2. Зачем нужны именованные конструкторы вроде User.guest()?
AЧтобы класс работал быстрее
BЧтобы создавать объект разными способами под разные сценарии
CЧтобы запретить создание объектов
DЭто устаревший синтаксис