Qu’est-ce qu’une classe et un objet
Une classe correspond à une catégorie, une classification. On abstrait les objets qui nous entourent pour en faire un type unique. Par exemple, on abstrait tous les êtres humains du monde entier pour créer la classe « Humain ». Une personne concrète, comme Bob ou Tom, est alors un objet.
Une classe agit comme un « plan » ou un « modèle » qui définit la structure et les comportements des objets.
Prenons encore l’exemple de la classe Humain : cette classe est un modèle. Qu’a un humain ? Un nom, des membres et des organes ; il peut parler et réfléchir. Les informations comme le nom ou l’âge sont des caractéristiques, appelées propriétés de la classe. Les actions comme parler ou réfléchir sont ses comportements. Autrement dit, une classe extrait un schéma commun à des éléments réels. Grâce à ce schéma, on peut créer des objets distincts comme Jack ou Jim.
Les propriétés d’une classe (nom, âge) et ses comportements (parler, réfléchir) se représentent respectivement par des variables et des fonctions.
Elle liste les propriétés (variables) et les méthodes (fonctions) que chaque objet doit posséder.
Une classe est comparable à un moule à pain : ce n’est pas un produit fini. On utilise le même moule pour fabriquer plusieurs pains concrets.
Au début de l’histoire de la programmation, le concept de classe n’existait pas. Le langage C en est un exemple : il ne dispose que de fonctions, de variables et d’instructions. On parle alors de programmation procédurale. À mesure que les logiciels se complexifiaient, les développeurs ont constaté de nombreux inconvénients avec ce paradigme : masses de code dupliqué, organisation désordonnée, manque de hiérarchie et de lisibilité. Plus tard, une nouvelle approche est apparue : abstraire la logique de programme en objets, à l’image du monde réel. On peut faire le parallèle avec une petite entreprise : au début, le patron gère toutes les tâches seul. Lorsqu’il embauche du personnel, il confie la comptabilité à un service financier et le recrutement aux ressources humaines. Chaque équipe a sa mission, et l’organisation devient beaucoup plus claire.
Un objet est une instance d’une classe.
Lorsque vous utilisez le mot-clé new ou un constructeur, la classe génère un objet.
L’objet est une entité concrète, capable de stocker des données et d’appeler des méthodes.
Relation entre classes et objets
- La classe est le plan architectural ; l’objet est la maison construite à partir de ce plan.
- Une même classe permet de créer plusieurs objets, chacun possédant ses propres données indépendantes.
- Tous les objets issus d’une même classe partagent les comportements (méthodes) définis dans la classe.

Passons maintenant au langage Dart
Nous allons aborder les points suivants
Dart est un langage orienté objet à part entière : toute valeur est une instance de classe. À l’exception de Null, toutes les classes héritent de la classe de base Object.
Dart implémente l’héritage grâce à l’association des classes et des Mixins
Héritage simple : chaque classe ne peut avoir qu’une seule classe parente, mais les Mixins permettent de réutiliser plusieurs ensembles de logiques de classe
Méthodes d’extension : ajouter des fonctionnalités à une classe sans modifier son code source ni créer une sous-classe
Modificateurs de classe : contrôler si d’autres bibliothèques peuvent hériter de cette classe ou l’implémenter
Commençons à étudier les classes en Dart
Membres de classe
Les membres d’une classe regroupent ses méthodes et ses variables : ce sont les éléments qui composent la classe.
Utilisez l’opérateur . pour accéder aux membres d’instance ; l’opérateur de sécurité null ?. évite les exceptions de pointeur nul
Voici un exemple complet qui montre comment définir une classe, instancier un objet à partir de cette classe et appeler ses membres par le nom de l’objet
// Définir une classe, équivaut à créer un moule
class Point {
double x, y;
Point(this.x, this.y);
// Méthode d'instance : calculer le carré de la distance entre deux points
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
// Créer l'objet p à partir de la classe Point pour réaliser des opérations
var p = Point(2, 2);
// Lire une variable d'instance (getter implicite)
print(p.y); //2.0
// Appeler une méthode d'instance
double dist = p.distanceTo(Point(4, 4));
print(dist); // 8.0
// Accès sécurisé avec ?.
Point? nullablePoint;
var a = nullablePoint?.y; // Si l'objet est null, a reçoit null sans erreur
print(a); // null
}Langage du code : JavaScript (javascript)

Constructeurs
Constructeurs standards
Dart se distingue des autres langages de type C par la prise en charge des constructeurs nommés. Dans la plupart des langages dérivés du C, le constructeur doit porter le même nom que la classe ; Dart permet de définir des constructeurs avec un identifiant différent du nom de la classe.
Syntaxe : NomClasse() / NomClasse.identifiant() ;
Le mot-clé new est facultatif (disponible depuis Dart 2)
class Point {
double x, y; // Deux variables membres qui stockent les propriétés de la classe
// Constructeur par défaut : initialiser les variables x et y
Point(this.x, this.y);
// Constructeur nommé Point.fromJson : initialiser x et y à partir de données JSON
Point.fromJson(Map<String, double> json)
: x = json['x']!,
y = json['y']!;
}
void main() {
var p1 = Point(2, 2);// Appel du constructeur par défaut, x=2 et y=2 pour p1
var p2 = Point.fromJson({'x': 1, 'y': 2}); // Utiliser le constructeur nommé fromJson avec un JSON
// new est optionnel, le comportement est identique
var p3 = new Point(3, 3); // Utiliser le constructeur par défaut
print("p1:(${p1.x},${p1.y}), p2:(${p2.x},${p2.y}), p3:(${p3.x},${p3.y})");
// Résultat : p1:(2.0,2.0), p2:(1.0,2.0), p3:(3.0,3.0)
}Langage du code : JavaScript (javascript)
Constructeurs constants avec const
Ajoutez le mot-clé const devant un constructeur pour créer des objets constants au moment de la compilation ; les constantes avec des paramètres identiques réutilisent la même instance.
class ImmutablePoint {
final double x, y;
// Règle du constructeur constant : tous les membres doivent être déclarés final
const ImmutablePoint(this.x, this.y);
}
void main() {
// Création d'instances constantes
var a = const ImmutablePoint(1, 1); // Le mot-clé const est obligatoire ici
var b = const ImmutablePoint(1, 1);
print(identical(a, b)); // true, ce sont le même objet
var m = const ImmutablePoint(1, 1);
var n = const ImmutablePoint(2, 1);
print(identical(m, n)); // false, des valeurs différentes créent des objets distincts
// Sans const : objet ordinaire, pas de partage d'instance
var c = ImmutablePoint(1, 1);
print(identical(a, c)); //false
// Dans un contexte const, le const interne peut être omis
const pointMap = {
'p1': [ImmutablePoint(0, 0)],
'p2': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)]
};
print(pointMap); //{p1: [Instance of 'ImmutablePoint'], p2: [Instance of 'ImmutablePoint', Instance of 'ImmutablePoint']}
print(identical(p1, p2)); // false
print(identical(p2, p3)); // false
print(identical(p1, p3)); // false
}Langage du code : PHP (php)
Un constructeur constant ne réutilise une instance que si tous les paramètres fournis sont strictement identiques ; un seul paramètre différent crée deux objets indépendants.
Récupérer le type d’exécution d’un objet avec runtimeType
Obtenez le type au moment de l’exécution via objet.runtimeType ; préférez l’opérateur de vérification de type is plutôt que des comparaisons sur runtimeType
class Point {
double x, y;
Point(this.x, this.y);
// Méthode d'instance : calculer le carré de la distance entre deux points
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return dx * dx + dy * dy;
}
}
void main() {
var p = Point(2, 3);
print("Type de p : ${p.runtimeType}"); // Point
// Méthode recommandée et stable
if (p is Point) {
print("p est une instance de Point");
}
// Non recommandé pour du code de production
if (p.runtimeType == Point) {
print("p est une instance de Point ");
}
}Langage du code : JavaScript (javascript)
Variables d’instance Instance Variables
- Les types nullables non initialisés valent par défaut
null; les types non nullables doivent obligatoirement être initialisés - Toutes les variables d’instance génèrent automatiquement un getter ; les variables non final ou late final sans initialisation génèrent un setter automatique
- Les expressions d’initialisation classiques des variables d’instance ne peuvent pas accéder à this ; les variables late autorisent l’accès à this dans leur initialisation
- Les variables d’instance final ne peuvent recevoir une valeur qu’une seule fois : à la déclaration, par paramètre de constructeur ou dans la liste d’initialisation du constructeur
Getters et setters implicites
class Point {
double? x; // Valeur initiale null, getter + setter générés automatiquement
double? y;
double z = 0; // Initialisé à 0
}
void main() {
var point = Point();
point.x = 4; // Appel du setter implicite
assert(point.x == 4); // Appel du getter implicite
assert(point.y == null);
print(point.z); // 0
}
Langage du code : JavaScript (javascript)
Restriction d’accès à this dans les expressions d’initialisation
double globalX = 1.5;
class Point {
// Autorisé : accéder à une variable globale externe sans recourir à this
double? x = globalX;
// Erreur de compilation : l’initialisation standard n’autorise pas this
// double? y = this.x;
// Autorisé : les variables late peuvent utiliser this dans leur initialisation
late double? z = this.x;
// Autorisé : le sucre syntaxique this.x des paramètres de constructeur n’est pas une expression d’initialisation
Point(this.x, this.y);
double? y;
}
void main() {
var p = Point(null, 5);
print(p.z); // null
}
Langage du code : JavaScript (javascript)
Trois manières d’initialiser les variables d’instance final
class ProfileMark {
// Méthode 1 : initialisation directe à la déclaration
final DateTime start = DateTime.now();
final String name;
// Méthode 2 : affectation par paramètre de constructeur
ProfileMark(this.name);
// Méthode 3 : affectation dans la liste d’initialisation du constructeur ; le constructeur nommé unnamed attribue une chaîne vide par défaut à name
ProfileMark.unnamed() : name = '';
}
void main() {
var m1 = ProfileMark("user1");
var m2 = ProfileMark.unnamed();
print(m1.name);
print(m2.name);
}
Langage du code : PHP (php)
Interfaces implicites Implicit interfaces
Chaque classe Dart possède une interface implicite qui regroupe tous ses membres d’instance publics.
implements: implémenter une interface, il faut redéfinir l’intégralité des méthodes de l’interfaceextends: hériter d’une classe parente pour réutiliser son implémentation- Les variables privées préfixées par
_xxxne sont pas exposées dans l’interface
1 Implémenter une seule interface
class Person {
final String _name;
Person(this._name);
// Méthode publique de l’interface
String greet(String who) => "Hello $who, I'm $_name";
}
// Implémenter l’interface Person : obligation de redéfinir tous ses membres
class Impostor implements Person {
String get _name => "";
@override
String greet(String who) => "Hi $who, guess who?";
}
String greetBob(Person p) => p.greet("Bob");
void main() {
print(greetBob(Person("Kathy")));
print(greetBob(Impostor()));
}
Langage du code : PHP (php)
Lorsqu’une sous-classe redéfinit une méthode de l’interface parente, utilisez l’annotation @override, comme en Java. On utilise le mot-clé implements pour implémenter une interface.

2 Implémenter plusieurs interfaces
// Classe abstraite
abstract class Comparable {
int compareTo(Object other);
}
// Classe abstraite
abstract class Location {
double get x;
double get y;
}
// Implémenter deux interfaces simultanément
class Point implements Comparable, Location {
@override
double x, y;
Point(this.x, this.y);
@override
int compareTo(Object other) {
if (other is Point) {
return (x + y).compareTo(other.x + other.y);
}
return -1;
}
}
void main() {
var p = Point(2, 3);
print(p.x);
print(p.compareTo(Point(1, 1)));
}
Langage du code : PHP (php)
@override
double x, y;
Cette annotation signifie que ces deux propriétés redéfinissent les getters abstraits déclarés dans l’interface parente Location.
Variables statiques & méthodes statiques static
1. Variables statiques static (variables de classe, unique au niveau global)
- Elles appartiennent à la classe et non aux instances ; initialisation paresseuse : elles ne sont créées qu’à leur premier accès
- Il est recommandé de nommer les constantes statiques en camelCase minuscule
class Queue {
static const initialCapacity = 16; // Variable statique constante
static int count = 0; // Variable statique mutable
Queue() {
count++;
}
}
void main() {
assert(Queue.initialCapacity == 16); // Initialisée à l’accès, valeur par défaut 16
Queue(); // Incrémenter count de 1
Queue();
print(Queue.count); // 2
}
Langage du code : JavaScript (javascript)
2. Méthodes statiques static (méthodes de classe)
- Pas de référence
this, impossible d’accéder aux membres d’instance ; seul accès autorisé aux variables statiques - Appel direct via la syntaxe
NomClasse.methode() - Peuvent être transmises comme constantes de compilation à des constructeurs constants
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
// Méthode statique : calculer la distance entre deux points
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var dist = Point.distanceBetween(a, b);
print(dist); // ~2,828
}Langage du code : JavaScript (javascript)

Les méthodes statiques appartiennent à la classe, il faut donc les appeler par le nom de la classe et transmettre deux instances de Point en paramètres.