constructeur

Qu’est-ce qu’un constructeur

Un constructeur est une fonction spéciale servant à créer des instances de classe, généralement chargée d’initialiser les propriétés. À l’exception du constructeur par défaut, tous les constructeurs portent le même nom que la classe.

Classification des constructeurs Dart :

  1. Constructeur génératif (Generative)
  2. Constructeur par défaut (Default)
  3. Constructeur nommé (Named)
  4. Constructeur constant (Const)
  5. Constructeur de redirection (Redirecting)
  6. Constructeur usine (Factory)
  7. Constructeur usine de redirection
  8. Syntaxe de constructeur concise (Dart 3.13+)
  9. Constructeur principal (Primary Constructors, champs minimalistes + syntaxe constructeur)

1. Constructeur génératif Generative Constructor

Constructeur de base, il crée des instances et initialise les variables membres. Il prend en charge les paramètres d’initialisation this.variable qui simplifient l’affectation.

class Point {
  double x;
  double y;

  // Constructeur génératif, this.x reçoit directement le paramètre pour affecter le membre
  Point(this.x, this.y); // Affecte directement des valeurs à x et y
}

void main() {
  final p = Point(10, 20);
  print("(${p.x}, ${p.y})"); // (10, 20)
}
Langage du code : JavaScript (javascript)

2. Constructeur par défaut Default Constructor

Si aucune fonction constructeur n’est définie manuellement dans une classe, Dart fournit automatiquement un constructeur génératif sans paramètres et sans nom. Ce fonctionnement est identique aux autres langages de type C comme C++, Java, C#, etc.

class PointA {
  double x = 0;
  double y = 0;
  // Constructeur par défaut implicite : PointA();
}

void main() {
  final p = PointA(); // Appel automatique du constructeur par défaut
  print("(${p.x}, ${p.y})"); // (0.0, 0.0)
}
Langage du code : PHP (php)

Attention : dès que vous écrivez manuellement un constructeur quelconque, le constructeur par défaut disparaît.

3. Constructeur nommé Named Constructor

Rôle : définir plusieurs constructeurs dans une même classe avec une sémantique claire ; format NomClasse.NomConstructeur()

const double xOrigin = 0;
const double yOrigin = 0;

class Point {
  final double x;
  final double y;

  // Constructeur génératif principal
  Point(this.x, this.y);

  // Constructeur nommé : point d'origine
  Point.origin() : x = xOrigin, y = yOrigin;
}

void main() {
  final p1 = Point(5, 6);
  final p2 = Point.origin(); // Appel du constructeur nommé
  print(p1.x); //5
  print("Point d'origine : (${p2.x}, ${p2.y})"); // (0,0)
}
Langage du code : PHP (php)

Règles essentielles

  • Les sous-classes n’héritent pas des constructeurs nommés de la classe parent ; si vous avez besoin d’un constructeur nommé identique dans la sous-classe, vous devez l’implémenter manuellement ;
  • Les constructeurs nommés prennent en charge la liste d’initialisation pour affecter des valeurs aux variables final.

4. Constructeur constant Const Constructor

Utilisé pour créer des objets constants à la compilation, conditions requises :

  1. Toutes les variables membres doivent être marquées final
  2. Ajoutez le mot-clé const au constructeur ; utilisez const lors de l’instanciation pour réutiliser le cache des constantes. Si vous omettez const, une instance ordinaire sera créée.
class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0); // Statique appartenant à la classe, partagé par toute la classe
  final double x, y;

  // Le constructeur constant peut initialiser x et y déclarés final
  const ImmutablePoint(this.x, this.y);
}

void main() {
  // Constante de compilation, réutilisation du même objet
  const p1 = ImmutablePoint(1, 2);
  const p2 = ImmutablePoint(1, 2); // Les paramètres transmis doivent être identiques, sinon ce sont des objets distincts
  print(p1 == p2); // true

  // Instance ordinaire, nouvel objet
  final p3 = ImmutablePoint(1, 2);
  print(p1 == p3); // false
}Langage du code : PHP (php)

5. Constructeur de redirection Redirecting Constructor

Constructeur qui transfère l’exécution vers un autre constructeur de la même classe avec la syntaxe : this(paramètres), le corps de la fonction doit être vide.

class Point {
  double x, y;

  // Constructeur principal
  Point(this.x, this.y);

  // Constructeur de redirection : ne transmet que x, y fixé à 0, renvoie vers le constructeur principal
  Point.alongX(double x) : this(x, 0); // Appelle le constructeur nommé puis transmet x au constructeur principal tout en affectant y=0
}

void main() {
  final p = Point.alongX(9);
  print("x=${p.x}, y=${p.y}"); // x=9, y=0
}
Langage du code : JavaScript (javascript)

6. Constructeur usine Factory Constructor

Mot-clé factory, cas d’utilisation adaptés :

  1. Ne crée pas systématiquement un nouvel objet (réutilisation du cache, renvoi d’instances de sous-classe)
  2. Logique complexe avant construction (analyse JSON, validation des paramètres). Restriction : impossible d’accéder à this
Exemple de singleton Logger avec cache
class Logger {
  final String name;
  bool mute = false;
  // Cache privé visible uniquement dans la bibliothèque
  static final Map<String, Logger> _cache = {};

  // Constructeur usine : récupère d'abord depuis le cache
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  // Constructeur usine : créer à partir de l'analyse json
  factory Logger.fromJson(Map<String, dynamic> json) {
    return Logger(json["name"].toString());
  }

  // Constructeur génératif interne privé
  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

void main() {
  final log1 = Logger("UI");
  final log2 = Logger("UI");
  print(log1 == log2); // true, même objet du cache

  final jsonLog = Logger.fromJson({"name": "Net"});
  jsonLog.log("request success");
}
Langage du code : JavaScript (javascript)

7. Constructeur usine de redirection Redirecting Factory

Syntaxe factory Nom() = ConstructeurAutreClasse;, adapté aux classes abstraites qui délèguent la création d’instances, évite de redéfinir les paramètres à plusieurs reprises.

abstract class Listenable {}

class _MergingListenable implements Listenable {
  List<_MergingListenable> list;
  _MergingListenable(this.list);
}

// Usine de redirection, appelle le constructeur de la classe privée interne
factory Listenable.merge(List<Listenable> list) = _MergingListenable;
Langage du code : PHP (php)

8. Détachement de constructeur Constructor Tear-offs

Passez directement le constructeur en argument de fonction sans écrire (), remplace les fonctions anonymes lambda redondantes pour de meilleures performances.

Écriture recommandée
void main() {
  final charCodes = [65, 66, 67];
  // Constructeur nommé String.fromCharCode
  final strs = charCodes.map(String.fromCharCode);
  print(strs); // (A, B, C)

  // Détachement de constructeur sans nom avec .new
  final buffers = charCodes.map(StringBuffer.new);
}
Langage du code : PHP (php)
Non recommandé : lambda superflu
// Encapsulation inutile, à éviter
charCodes.map((code) => String.fromCharCode(code));
Langage du code : JavaScript (javascript)

9. Syntaxe de constructeur concise (Dart 3.13+) Concise Constructor

À l’intérieur de la classe, vous pouvez omettre le nom de la classe, utilisez directement new / factory pour définir les constructeurs sans écrire NomClasse.xxx :

Syntaxe traditionnelleRaccourci
Point(this.x,this.y)new(this.x,this.y)
Point.origin():x=0,y=0new origin():x=0,y=0
factory Point.clone()factory clone()
class Point {
  double x, y;

  // Constructeur génératif sans nom raccourci
  new(this.x, this.y);

  // Constructeur génératif nommé raccourci
  new origin() : x = 0, y = 0;

  // Constructeur usine raccourci
  factory clone(Point other) => new(other.x, other.y);
}

void main() {
  final p = new(3, 4);
  final origin = new origin();
  final copy = p.clone(p);
}
Langage du code : PHP (php)

10. Trois manières d’initialiser les variables d’instance

1 : Affectation directe à la déclaration
class PointA {
  double x = 1.0;
  double y = 2.0;
}
Langage du code : JavaScript (javascript)

2 : Paramètres d’initialisation

this.variable

Prend en charge les paramètres positionnels optionnels, paramètres nommés et variables nullables

class PointB {
  final double x;
  final double y;

  // Paramètres positionnels optionnels
  PointB.opt([this.x = 0, this.y = 0]);

  // Paramètres nommés avec valeur par défaut
  PointB.named({this.x = 5, this.y = 5});
}
Langage du code : JavaScript (javascript)

3 : Liste d’initialisation Initializer List

Affectation après le deux-points :, s’exécute avant le corps du constructeur, ne peut pas accéder à this, prend en charge assert pour la validation des paramètres.

class Point {
  final double x;
  final double y;

  Point.fromJson(Map<String, double> json)
      : x = json["x"]!,
        y = json["y"]! {
    print("Corps du constructeur exécuté, x=$x");
  }

  // Avec validation par assertion
  Point.withAssert(this.x, this.y) : assert(x >= 0);
}
Langage du code : JavaScript (javascript)

11. Paramètres d’initialisation directs des champs privés (Dart3.12+)

Pour les variables privées préfixées d’un underscore, écrivez les paramètres du constructeur sous la forme this._champ ; lors de l’appel externe, utilisez directement le nom public sans underscore.

class Point {
  final double _x;
  final double _y;

  // Interne _x, appel externe s'écrit x:10
  Point({required this._x, this._y = 0});
}

void main() {
  final p = Point(x: 10); // Pas besoin d'écrire _x, directement x
  print(p._x); // 10
}
Langage du code : PHP (php)

Utilisez le nom d’origine de la variable privée dans la liste d’initialisation :

class Point {
  final double _x;
  Point({required this._x}) : assert(_x > 0);
}
Langage du code : JavaScript (javascript)

12. Constructeurs de la classe parent et règles d’héritage

  1. Les sous-classes n’héritent d’aucun constructeur de la classe parent ;
  2. Ordre d’exécution du constructeur : liste d’initialisation → constructeur parent → corps du constructeur de la sous-classe ;
  3. Si la classe parent ne dispose pas de constructeur par défaut sans paramètres, la sous-classe doit appeler manuellement super() pour désigner le constructeur parent.
Exemple d’appel super basique

Comme en Java, on utilise super pour désigner la classe de base ; en C#, on utilise base.

class Person {
  final String name;
  Person(this.name);
  Person.fromMap(Map map) : name = map["name"];
}

class Employee extends Person {
  int id;
  // Appel du constructeur nommé de la classe parent
  Employee(Map data) : super.fromMap(data), id = data["id"];
}
Langage du code : JavaScript (javascript)

Attention : l’expression des paramètres de super ne peut pas utiliser this.

Paramètres Super (Dart2.17+, simplifie la transmission des paramètres au parent)

Utilisez super.variable pour transmettre directement les paramètres au constructeur parent sans écrire manuellement super(x,y)

class Vector2d {
  final double x, y;
  Vector2d(this.x, this.y);
}

class Vector3d extends Vector2d {
  final double z;
  // super.x super.y transmettent automatiquement vers le constructeur parent
  Vector3d(super.x, super.y, this.z);
}

// Constructeur nommé parent + paramètres nommés super
class Vector3dYZ extends Vector2d {
  final double z;
  Vector3dYZ({required super.y, required this.z}) : super.named(x: 0);
}
Langage du code : JavaScript (javascript)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *