Ответ
Перегрузка конструкторов — это возможность языка определять несколько конструкторов с одним именем, но разными параметрами. Dart не поддерживает перегрузку методов или конструкторов в классическом понимании (как Java или C#).
Вместо этого Dart предлагает несколько гибких механизмов для достижения той же цели — создания объектов разными способами:
-
Именованные конструкторы: Основной способ. Позволяют дать конструктору явное имя для описания его цели.
class Point { double x, y; Point(this.x, this.y); // Основной конструктор Point.origin() : this(0, 0); // Именованный конструктор Point.fromJson(Map<String, double> json) : x = json['x']!, y = json['y']!; } var p1 = Point(5, 10); var p2 = Point.origin(); var p3 = Point.fromJson({'x': 1.0, 'y': 2.0}); -
Необязательные параметры с значениями по умолчанию: Позволяют одному конструктору покрывать множество случаев.
- Именованные параметры (
{}): Удобны, когда нужно указать только некоторые параметры. -
Позиционные параметры (
[]): Редко используются для конструкторов.class Rectangle { int width; int height; Color color; // Один конструктор с необязательными именованными параметрами Rectangle({ this.width = 100, this.height = 100, this.color = Colors.blue, }); }
var rect1 = Rectangle(); // 100x100, синий var rect2 = Rectangle(width: 200, color: Colors.red); // 200x100, красный
- Именованные параметры (
-
Фабричный конструктор (
factory): Полезен, когда логика создания экземпляра сложная: возврат существующего объекта (например, из кэша), создание объекта подкласса или асинхронная инициализация (хотя для асинхронности лучше использовать статический метод).class Logger { final String name; static final Map<String, Logger> _cache = <String, Logger>{}; factory Logger(String name) { return _cache.putIfAbsent(name, () => Logger._internal(name)); } Logger._internal(this.name); // Приватный конструктор } var logger1 = Logger('app'); var logger2 = Logger('app'); // Вернёт тот же экземпляр из кэша
Эти подходы в Dart часто оказываются даже более выразительными и удобными, чем классическая перегрузка.
Ответ 18+ 🔞
А, ну это же классика, ёпта! Сидишь такой, переползаешь с Java или C#, и тут — бац! — а в Dart перегрузки конструкторов, как ты привык, нихуя нет. Совсем. Никаких там Point(int x), Point(double x), Point(int x, int y) с одним именем. Ядрёна вошь, думаешь, приехали.
Но не спеши материться, чувак. Дарт — он хитрая жопа. Он просто подходит к вопросу с другой стороны, и, если честно, часто это даже удобнее получается. Смотри, какие у него фокусы в рукаве.
1. Именованные конструкторы — наш главный козырь
Вот это, бля, основа основ. Не перегружать один метод, а дать каждому способу создания своё говорящее имя. Красота же!
class Point {
double x, y;
Point(this.x, this.y); // Ну, стандартный, понятно
// А это что за зверь? Именованный, мать его!
Point.origin() : this(0, 0); // Создаёт точку в начале координат. Сразу ясно, что происходит!
Point.fromJson(Map<String, double> json) // А этот из JSON выковыривает данные
: x = json['x']!,
y = json['y']!;
}
// Используется — загляденье!
var p1 = Point(5, 10); // Классика
var p2 = Point.origin(); // О, сразу видно — ноль-ноль!
var p3 = Point.fromJson({'x': 1.0, 'y': 2.0}); // И тут всё прозрачно, ебать копать.
Чувствуешь разницу? Не надо гадать, какой из десяти Point() сработает. Видишь имя — понимаешь намерение. Удивление пиздец, как же это читаемо!
2. Один конструктор на все случаи жизни (с параметрами по умолчанию)
А вот это для ленивых, как я. Зачем три конструктора, если можно запихать всю логику в один, но с такими плюшками, что мама не горюй?
class Rectangle {
int width;
int height;
Color color;
// Смотри, один конструктор, но в нём — овердохуища возможностей!
Rectangle({
this.width = 100, // Если не укажешь — будет 100
this.height = 100, // И тут 100
this.color = Colors.blue, // И по умолчанию синий, красота!
});
}
// И твори, что хочешь!
var rect1 = Rectangle(); // Без параметров? Да похуй! 100x100, синий.
var rect2 = Rectangle(width: 200, color: Colors.red); // А тут только ширину и цвет поменял. Идеально!
Именованные параметры ({}) — это просто песня. Указывай что нужно, остальное само подставится. Никакой путаницы с порядком аргументов, как в позиционной перегрузке. Волнение ебать, как же удобно!
3. Фабричный конструктор (factory) — для сложных делишек
А вот это уже магия по-взрослому. Когда нужно не просто поля присвоить, а какую-то хитрожопую логику выполнить при создании объекта.
class Logger {
final String name;
static final Map<String, Logger> _cache = <String, Logger>{}; // Кеш, сука!
// Фабрика! Она может решить, что тебе вернуть.
factory Logger(String name) {
// Смотри: если объект с таким именем уже есть — вернёт старый. Нет — создаст новый.
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
Logger._internal(this.name); // А это приватный конструктор, чтоб с улицы не дёргали.
}
var logger1 = Logger('app'); // Создаст новый
var logger2 = Logger('app'); // А тут, бля, вернёт тот же самый экземпляр из кэша! Ни хуя себе!
factory — это мощь. Кеширование, возврат объектов подклассов, любая нестандартная инициализация. Пизда рулю! Хотя для асинхронной загрузки данных лучше статический метод использовать, но это уже другая история.
Короче, вывод какой? Да, в Dart нет той перегрузки, к которой ты, возможно, привык. Но то, что предлагают вместо неё — именованные конструкторы, параметры по умолчанию и фабрики — это часто даже лучше. Код становится понятнее, намерения видны как на ладони, и меньше шансов накосячить, передав аргументы не в том порядке. Привыкаешь быстро, а потом вообще удивляешься, как без этого жил.