Ответ
В Dart есть несколько типов конструкторов, каждый решает свою задачу:
1. Стандартный конструктор:
class Point {
double x, y;
Point(this.x, this.y); // Сокращённая инициализация
}
2. Именованный конструктор (named constructor): Позволяет создавать объекты альтернативными способами.
class Point {
double x, y;
Point(this.x, this.y);
Point.origin() : x = 0, y = 0; // Именованный конструктор
Point.fromJson(Map<String, double> json) : x = json['x']!, y = json['y']!;
}
3. Конструктор с перенаправлением (redirecting constructor): Перенаправляет вызов другому конструктору того же класса.
class Point {
double x, y;
Point(this.x, this.y);
Point.alongXAxis(double x) : this(x, 0); // Вызывает Point(x, 0)
}
4. Фабричный конструктор (factory constructor): Используется, когда создание экземпляра требует логики (кеширование, возврат подтипа).
class Logger {
final String name;
static final Map<String, Logger> _cache = {};
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
Logger._internal(this.name); // Приватный конструктор
}
5. Константный конструктор (const constructor):
Создаёт compile-time константы, все поля должны быть final.
class ImmutablePoint {
final double x, y;
const ImmutablePoint(this.x, this.y);
}
// Использование:
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2);
print(identical(p1, p2)); // true — это один и тот же объект в памяти Ответ 18+ 🔞
Э, слушай, а вот Dart, он, блядь, такой разносторонний, что конструкторов у него — овердохуища разных видов. Прям как инструменты в гараже: каждый для своего дела, а если перепутаешь — получишь пиздопроебибну в коде. Сейчас разжую, как есть.
1. Обычный, как две копейки.
Ну тут всё просто, ёпта. Создал класс — написал конструктор. Dart ещё любезно позволяет сократить эту писанину через this. — красота же!
class Point {
double x, y;
Point(this.x, this.y); // Всё, готово, нехуй тут философствовать
}
2. Именованный — когда одного способа создания мало.
Бывает же, что объект можно собрать из разных источников? Вот для этого они и нужны. Назвал как хочешь — и вперёд.
class Point {
double x, y;
Point(this.x, this.y);
Point.origin() : x = 0, y = 0; // Нулевая точка, классика
Point.fromJson(Map<String, double> json) : x = json['x']!, y = json['y']!; // Из JSON, модно-молодёжно
}
3. Перенаправляющий — ленивая жопа.
Зачем писать одну и ту же логику дважды, если можно просто ткнуть пальцем в другой конструктор и сказать: «Сам делай!». Экономия времени, ядрёна вошь.
class Point {
double x, y;
Point(this.x, this.y);
Point.alongXAxis(double x) : this(x, 0); // По сути, кричим: «Эй, Point(x, 0), сделай за меня работу!»
}
4. Фабричный — хитрая жопа.
Вот это уже интереснее. Тут тебе и кеширование, и выбор подтипа, и вообще любая логика перед созданием объекта. Но будь осторожен, а то доверия ебать ноль к таким штукам — легко накосячить.
class Logger {
final String name;
static final Map<String, Logger> _cache = {};
factory Logger(String name) {
// Смотри, не создаём новый логгер, если уже есть с таким именем — умно, да?
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
Logger._internal(this.name); // А это приватный конструктор, чтоб с улицы не дёргали
}
5. Константный — для перфекционистов.
Если все поля final и объект как с конвейера — одинаковый, можно сделать его константным. Тогда два одинаковых вызова вернут один и тот же объект в памяти, а не копии. Экономия, блядь, на уровне компилятора!
class ImmutablePoint {
final double x, y;
const ImmutablePoint(this.x, this.y);
}
// Использование:
const p1 = ImmutablePoint(1, 2);
const p2 = ImmutablePoint(1, 2);
print(identical(p1, p2)); // true — один объект, две ссылки. Красота!
Вот и вся магия. Главное — не путать, когда какой юзать, а то получится хуй в пальто, а не код. Удачи, чувак!