← Назад к вопросам

В чем разница между конструкторами обычным и именованным?

1.0 Junior🔥 221 комментариев
#Dart

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между обычным конструктором и именованным конструктором

В Dart есть два способа создать конструктор: обычный (стандартный) и именованный (named). Это важная фишка языка для создания удобных API классов.

Обычный конструктор

Обычный конструктор — это основной способ создания объекта класса. У класса может быть только ОДИН обычный конструктор.

class User {
  String name;
  int age;
  String email;
  
  // Обычный конструктор
  User(this.name, this.age, this.email);
}

// Создание объекта
var user = User('John', 30, 'john@example.com');

Именованный конструктор

Именованный конструктор — это дополнительные конструкторы с явным именем. Их может быть несколько, и каждый может иметь разную логику создания объекта.

class User {
  String name;
  int age;
  String email;
  
  // Обычный конструктор
  User(this.name, this.age, this.email);
  
  // Именованный конструктор
  User.admin(String name) : this(name, 0, 'admin@example.com');
  
  User.guest() : this('Guest', 18, 'guest@example.com');
  
  User.fromJson(Map<String, dynamic> json)
      : this(json['name'], json['age'], json['email']);
}

// Создание объектов через разные конструкторы
var user1 = User('John', 30, 'john@example.com');     // обычный
var user2 = User.admin('Alice');                      // именованный
var user3 = User.guest();                             // именованный
var user4 = User.fromJson({'name': 'Bob', 'age': 25, 'email': 'bob@example.com'});

Сравнение

ПараметрОбычный конструкторИменованный конструктор
КоличествоТолько одинМожет быть несколько
ИмяСовпадает с классомСвое имя
СинтаксисClassName(...)ClassName.name(...)
НазначениеСтандартное созданиеСпециализированные варианты
ИспользованиеОсновной способАльтернативные способы

Пример 1: Обычный конструктор

class Point {
  double x;
  double y;
  
  // Обычный конструктор — основной способ
  Point(this.x, this.y);
}

// Использование
var point = Point(10.0, 20.0);
print('${point.x}, ${point.y}');  // 10.0, 20.0

Пример 2: Несколько именованных конструкторов

class Point {
  double x;
  double y;
  
  Point(this.x, this.y);
  
  // Конструктор для создания точки в начале координат
  Point.origin() : this(0, 0);
  
  // Конструктор из другого типа данных
  Point.fromList(List<double> coords) : this(coords[0], coords[1]);
  
  // Конструктор из строки
  Point.parse(String str) {
    var parts = str.split(',');
    x = double.parse(parts[0]);
    y = double.parse(parts[1]);
  }
}

// Использование
var p1 = Point(10, 20);           // обычный
var p2 = Point.origin();            // (0, 0)
var p3 = Point.fromList([3, 4]);   // (3, 4)
var p4 = Point.parse('5,6');       // (5, 6)

Пример 3: JSON парсинг (очень популярный случай)

class Product {
  final String id;
  final String name;
  final double price;
  final String description;
  
  // Обычный конструктор для прямого использования
  Product(
    this.id,
    this.name,
    this.price,
    this.description,
  );
  
  // Именованный конструктор для парсинга JSON из API
  Product.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        name = json['name'],
        price = (json['price'] as num).toDouble(),
        description = json['description'] ?? '';
  
  // Конструктор для создания dummy продукта
  Product.dummy()
      : id = 'dummy',
        name = 'Dummy Product',
        price = 0.0,
        description = 'This is a dummy';
}

// Использование в приложении
final json = {'id': '123', 'name': 'Phone', 'price': 999.99, 'description': 'Cool phone'};
var product1 = Product.fromJson(json);  // из JSON
var product2 = Product.dummy();          // dummy для тестов
var product3 = Product('456', 'Laptop', 1299.99, 'Powerful');

Реальный пример из Flutter: DateTime

// У DateTime есть несколько конструкторов

// Обычный конструктор
var date1 = DateTime(2025, 3, 26, 10, 30, 0);

// Именованные конструкторы
var now = DateTime.now();              // текущее время
var utcTime = DateTime.utc(2025, 3, 26);
var parsed = DateTime.parse('2025-03-26T10:30:00');

Практический пример: User модель

class User {
  final String id;
  final String name;
  final String email;
  final bool isAdmin;
  final DateTime createdAt;
  
  User({
    required this.id,
    required this.name,
    required this.email,
    this.isAdmin = false,
    required this.createdAt,
  });
  
  // Создание из JSON (с API)
  User.fromJson(Map<String, dynamic> json)
      : id = json['id'],
        name = json['name'],
        email = json['email'],
        isAdmin = json['isAdmin'] ?? false,
        createdAt = DateTime.parse(json['createdAt']);
  
  // Для тестирования
  User.test()
      : id = 'test-id',
        name = 'Test User',
        email = 'test@example.com',
        isAdmin = false,
        createdAt = DateTime.now();
  
  // Для гостевого пользователя
  User.guest()
      : id = 'guest',
        name = 'Guest',
        email = 'guest@example.com',
        isAdmin = false,
        createdAt = DateTime.now();
  
  // Копирование с изменением некоторых полей
  User copyWith({
    String? name,
    String? email,
    bool? isAdmin,
  }) {
    return User(
      id: this.id,
      name: name ?? this.name,
      email: email ?? this.email,
      isAdmin: isAdmin ?? this.isAdmin,
      createdAt: this.createdAt,
    );
  }
}

// Использование
var user1 = User(
  id: '1',
  name: 'John',
  email: 'john@example.com',
  createdAt: DateTime.now(),
);

var user2 = User.fromJson(apiResponse);
var user3 = User.test();
var user4 = User.guest();

Именованные параметры конструктора

Дополнение: в Dart часто используют именованные параметры (named parameters) в конструкторах:

// Обычный конструктор с именованными параметрами
class User {
  String name;
  int age;
  
  User({
    required this.name,
    required this.age,
  });
}

// Создание (порядок не важен)
var user = User(name: 'John', age: 30);
var user2 = User(age: 25, name: 'Alice');

Когда использовать именованные конструкторы?

// Когда класс имеет несколько способов создания
class Color {
  int red, green, blue;
  
  // Из RGB
  Color(this.red, this.green, this.blue);
  
  // Из HEX
  Color.fromHex(String hex) { ... }
  
  // Из HSV
  Color.fromHsv(double h, double s, double v) { ... }
}

// Из файла
class ImageData {
  final Uint8List data;
  
  ImageData(this.data);
  
  ImageData.fromFile(File file) : data = file.readAsBytesSync();
  
  ImageData.fromUrl(String url) : data = _downloadImage(url);
}

Различие в коде

// Обычный конструктор
var user = User('John', 30, 'john@example.com');

// Именованный конструктор
var admin = User.admin('Alice');

// Очень очевидно что это разные варианты создания

Вывод: Обычный конструктор — это основной способ создания объекта (только один). Именованные конструкторы — это дополнительные, специализированные конструкторы для разных способов создания (может быть много). Это мощный инструмент для создания удобного API класса, особенно для парсинга JSON, копирования с изменениями, и создания специальных экземпляров (test, dummy, guest).