L’héritage des classes Dart
L’héritage des classes Dart
Objectifs du cours
- À la fin du cours, vous serez capables de créer une classe dérivée en Dart à partir d’une classe existante en utilisant le mot-clé
extends
. - Utiliser adéquatement le mot-clé
super
de manière appropriée pour appeler les constructeurs des classes parentes lors de la création de classes dérivées.
-
Introduction à l’Héritage en Dart
- En programmation, l’héritage est un concept fondamental qui permet la création de nouvelles classes en se basant sur des classes existantes. En Dart, un langage de programmation développé par Google, l’héritage est pris en charge de manière similaire à d’autres langages orientés objet tels que Java ou C++.
- L’héritage est le mécanisme par lequel on créé une classe B à partir d’une autre classe existante A.
- On dit alors que la classe B hérite de la classe A. Ainsi, la classe A est appelé « classe parente » ou « super classe » et la classe B est la « classe enfant » ou « sous classe« . L’héritage en Dart se fait en utilisant le mot clé extends.
- L’héritage est la pierre angulaire de la programmation objet. En utilisant le mot clé
extends
, vous pouvez permettre à une classe enfant d’hériter les propriétés et les méthodes d’une autre classe parente. De plus, la classe enfant a accès aux propriétés et méthodes de sa propre classe ainsi qu’à la classe de base. - En fait, dans le langage Dart, la classe Objet est la Super classe (parente) de toutes les classes. Par conséquent, chaque classe est dérivée d’au moins une classe ou a au moins une classe parente à l’exception de la classe Object.
-
Utilisation de l’Héritage en Dart
- En Dart, l’héritage est utilisé pour créer une relation de parenté entre les classes. La classe parente, également appelée superclasse ou classe de base, définit le comportement et les caractéristiques communes à un groupe de classes dérivées, appelées sous-classes ou classes dérivées.
- Les sous-classes héritent des membres (attributs et méthodes) de la superclasse et peuvent ajouter leurs propres membres spécifiques.
-
Définition d’une
classe de base
(superclasse
) : - En Dart, une classe de base, également appelée superclasse, est une classe dont d’autres classes peuvent hériter. Elle sert souvent de modèle ou de point de départ pour créer de nouvelles classes.
- Dans cet exemple, Animal est une classe de base avec deux propriétés (nom et age) et une méthode (faireDuBruit).
-
Définition d’une
sous-classe
qui hérite de lasuperclasse
- Pour hériter d’une classe de base en Dart, on utilise le mot-clé
extends
. Par exemple, voici comment créer une classe Chien qui hérite de la classe Animal : - La classe Chien hérite de la classe Animal. Elle utilise le mot-clé extends suivi du nom de la classe parente. Le constructeur de la classe fille utilise super pour appeler le constructeur de la classe parente avec les paramètres nécessaires.
-
Instanciation et utilisation de la
sous-classe
- Lorsque vous exécutez le code ci-dessus, vous obtiendrez la sortie suivante :
- Ce code montre comment une classe dérivée (Chien) peut hériter des propriétés et des méthodes d’une classe de base (Animal) en Dart. L’héritage permet la réutilisation du code et la création de hiérarchies de classes.
-
Déclarer un constructeur d’une sous-classe (ou classe dérivée)
- En Dart, pour déclarer un constructeur d’une sous-classe (ou classe dérivée), vous utilisez le mot-clé super pour appeler le constructeur de la superclasse. Voici comment vous pouvez déclarer un constructeur pour une sous-classe :
- Supposons que nous ayons une classe de base Animal :
- Et nous avons une sous-classe Dog qui hérite de la classe Animal :
- Dans cet exemple, le constructeur de la sous-classe Dog est déclaré avec la syntaxe suivante :
- Explications :
- Dog est le nom du constructeur.
String name, int age, this.breed
sont les paramètres du constructeur de la sous-classe.: super(name, age);
est l’appel au constructeur de la superclasse Animal avec les arguments name et age. Cela permet d’initialiser les propriétés name et age de la superclasse.-
Applications
-
TD01
- Objectifs du TD
- Ce TD à pour but de présenter le concept d’héritage en Dart. Il présente également un exercice sur la manipulation de tableau (via un exercice de tri).
- Rappel : Héritage
- Un cas concret : La classe Voiture représente toutes sortes de voitures possibles. On pourrait définir un camion comme une voiture très longue, très haute ? Mais un camion a des spécificités visà-vis des voitures : remorque,… On pourrait créer une classe Camion qui ressemble à la classe Voiture. Mais on ne veut pas réécrire tout ce qu’elles ont en commun.
- La solution : La classe Vehicule contient tout ce qu’il y a de commun à Camion et Voiture. Camion par exemple ne contient que ce qu’il y a de spécifique aux camions.
-
Exercice:01
- Supposons que l’on dispose de la classe Date suivante :
- On veut définir une classe DateEvenement qui associe à une date donnée un événement qui la caractérise. La solution triviale serait de définir la classe DateEvenement en redéfinissant cette classe en prenant exemple sur la classe Date et en ajoutant les nouvelles fonctionnalités que l’on juge utiles.
- Ecrire DateEvenement en utilisant l’héritage.
-
Exercice:02
- Ecrire une classe Animal qui dispose d’un attribut entier nbpattes. Cette classe dispose des méthodes suivantes :
- Le constructeur, qui prend en argument un entier (le nombre de pattes),
- String toString() qui renvoie une chaîne de caractères contenant le nombre de pattes de l’animal affiche() qui affiche le nombre de pattes de l’animal.
- Ecrire une classe Autruche qui hérite de Animal.
- Ecrire une classe Lapin qui hérite de Animal.
- Ecrire une classe Main dans laquelle la méthode main() crée un lapin et une autruche.
-
Exercice:03
- Soit le programme Dart suivant :
- a) La classe Circle hérite des variables d’instance x et y de la classe Shape. En Dart, l’héritage se fait implicitement lorsque vous étendez une classe, et les membres non privés de la classe parente sont accessibles dans la classe dérivée. Ainsi, Circle hérite des variables x et y de la classe Shape.
- b) Pour ajouter une méthode setRadius permettant de fixer la valeur du rayon et getRadius pour lire la valeur du rayon dans la classe Circle, vous pouvez effectuer les modifications suivantes :
- Dans ce code, _radius est déclaré comme une variable privée en utilisant _ au début du nom. Les méthodes setRadius et getRadius sont ajoutées pour modifier et lire la valeur du rayon respectivement.
- c) Pour ajouter une variable surface à la classe Circle et mettre à jour les méthodes setRadius et toString, vous pouvez procéder ainsi :
- Dans ce code, la variable surface est ajoutée, et les méthodes getSurface et calculateSurface sont introduites pour accéder à la surface et la calculer respectivement. La méthode setRadius est modifiée pour mettre à jour la surface après la modification du rayon.
-
Exercice:04
- Ecrivez une classe Bâtiment avec les attributs suivants:
- adresse
- La classe Bâtiment doit disposer des constructeurs suivants:
- Batiment(),
- Batiment (adresse).
- La classe Bâtiment doit contenir des accesseurs et mutateurs (ou propriétés) pour les différents attributs. La classe Bâtiment doit contenir une méthode ToString () donnant une représentation du Bâtiment.
- Ecrivez une classe Maison héritant de Bâtiment avec les attributs suivants:
- NbPieces: Le nombre de pièces de la maison.
- La classe Maison doit disposer des constructeurs suivants:
- Maison(),
- Maison(adresse, nbPieces).
- La classe Maison doit contenir des accesseurs et mutateurs (ou des propriétés) pour les différents attributs. La classe Maison doit contenir une méthode ToString () donnant une représentation de la Maison.
- Ecrivez aussi un programme afin de tester ces deux classes .
Dans Dart, l’héritage est implémenté via le mot-clé ‘
extends
‘. Lorsqu’une classe est déclarée hériter d’une autre classe, elle devient unesous-classe
et la classe dont elle hérite devient lasuperclasse
.
// Déclaration de la classe Animal.
class Animal {
// Propriété pour stocker le nom de l'animal.
String nom;
// Propriété pour stocker l'âge de l'animal.
int age;
// Constructeur de la classe Animal.
// Il prend le nom et l'âge en paramètres et initialise les propriétés correspondantes.
Animal(this.nom, this.age);
// Méthode faireDuBruit.
// Affiche un message indiquant que certains animaux font du bruit.
void faireDuBruit() {
print("Certains animaux font du bruit.");
}
}
// Déclaration de la classe Chien qui étend la classe Animal.
class Chien extends Animal {
// Constructeur de la classe Chien.
// Appelle le constructeur de la classe parente (Animal) en utilisant 'super'.
Chien(String nom, int age) : super(nom, age);
// Méthode aboyer.
// Affiche un message indiquant que le chien aboie, en utilisant le nom de l'animal.
void aboyer() {
print("$nom aboie : Woof! Woof!");
}
}
void main() {
var monChien = Chien("Buddy", 3);
print("Nom du chien : ${monChien.nom}");
print("Age du chien : ${monChien.age}");
monChien.faireDuBruit(); // Appelle la méthode de la classe parente
monChien.aboyer(); // Appelle la méthode spécifique à la classe fille
}
Nom du chien : Buddy
Age du chien : 3
Certains animaux font du bruit.
Buddy aboie : Woof! Woof!
class Animal {
String name;
int age;
Animal(this.name, this.age);
void eat() {
print('$name is eating.');
}
void sleep() {
print('$name is sleeping.');
}
}
class Dog extends Animal {
String breed;
// Constructeur de la sous-classe Dog
Dog(String name, int age, this.breed) : super(name, age);
void bark() {
print('$name is barking.');
}
}
Dog(String name, int age, this.breed) : super(name, age);
class Date {
int jour, mois, annee;
// Constructeur de la classe Date
Date(int j, int m, int a) {
jour = j;
mois = m;
annee = a;
}
// Méthode pour définir une nouvelle date
void setDate(int j, int m, int a) {
jour = j;
mois = m;
annee = a;
}
// Méthode pour obtenir une représentation sous forme de chaîne de la date
@override
String toString() {
return '$jour/$mois/$annee';
}
}
Solution
// Classe DateEvenement héritant de la classe Date
class DateEvenement extends Date {
String event;
// Constructeur de la classe DateEvenement
DateEvenement(int j, int m, int a, String e) : super(j, m, a) {
event = e;
}
// Méthode pour définir une nouvelle date et un nouvel événement
void setDateEvenement(int j, int m, int a, String e) {
super.setDate(j, m, a);
event = e;
}
// Méthode pour obtenir une représentation sous forme de chaîne de la date et de l'événement
@override
String toString() {
return '${super.toString()}->$event';
}
}
Solution
class Animal {
int nbPattes;
// Constructeur de la classe Animal
Animal(this.nbPattes);
// Méthode toString pour afficher le nombre de pattes
@override
String toString() {
return 'Nombre de pattes : $nbPattes';
}
// Méthode affiche() pour afficher le nombre de pattes
void affiche() {
print('Nombre de pattes : $nbPattes');
}
}
// Classe Autruche héritant de la classe Animal
class Autruche extends Animal {
// Constructeur de la classe Autruche
Autruche(int nbPattes) : super(nbPattes);
}
// Classe Lapin héritant de la classe Animal
class Lapin extends Animal {
// Constructeur de la classe Lapin
Lapin(int nbPattes) : super(nbPattes);
}
// Classe Main
void main() {
// Création d'une autruche avec 2 pattes
Autruche autruche = Autruche(2);
// Création d'un lapin avec 4 pattes
Lapin lapin = Lapin(4);
// Affichage des informations sur l'autruche
print('Informations sur l\'autruche:');
print(autruche.toString());
autruche.affiche();
// Affichage des informations sur le lapin
print('\nInformations sur le lapin:');
print(lapin.toString());
lapin.affiche();
}
import 'dart:math';
class Shape {
double x, y;
Shape() {
x = 0;
y = 0;
}
Shape.withCoordinates(double x, double y) {
this.x = x;
this.y = y;
}
String toString() {
return "Position : ($x, $y)";
}
}
class Circle extends Shape {
static const double PI = 3.141592564;
double radius;
Circle() : radius = 0;
Circle.withCoordinatesAndRadius(double x, double y, double r) : super.withCoordinates(x, y) {
radius = r;
}
@override
String toString() {
return super.toString() + " Rayon : $radius";
}
}
void main() {
Circle c1, c2;
c1 = Circle.withCoordinatesAndRadius(1, 1, 3);
c2 = Circle();
print('${c1.toString()}\n${c2.toString()}');
}
a) De quelles variables d’instance de shape hérite la classe Circle?
b) La variable radius étant déclarée private, on ne peut la modifier de l’extérieur de la classe. Ajouter une méthode setRadius pour pouvoir le fixer et getRadius pour le lire.
c) Ajoutez une variable surface à la classe Circle. Modifiez les méthodes setRadius et toString. Ajoutez les méthodes d’accès à ce champ.
Solution
class Circle extends Shape {
static const double PI = 3.141592564;
double _radius; // La variable radius est maintenant privée et commence par _
Circle() : _radius = 0;
Circle.withCoordinatesAndRadius(double x, double y, double r) : super.withCoordinates(x, y) {
_radius = r;
}
double getRadius() {
return _radius;
}
void setRadius(double radius) {
_radius = radius;
}
@override
String toString() {
return super.toString() + " Rayon : $_radius";
}
}
class Circle extends Shape {
static const double PI = 3.141592564;
double _radius;
double _surface; // Nouvelle variable surface
Circle() : _radius = 0, _surface = 0;
Circle.withCoordinatesAndRadius(double x, double y, double r) : super.withCoordinates(x, y) {
_radius = r;
_surface = calculateSurface();
}
double getRadius() {
return _radius;
}
void setRadius(double radius) {
_radius = radius;
_surface = calculateSurface(); // Mettre à jour la surface après modification du rayon
}
double getSurface() {
return _surface;
}
double calculateSurface() {
return PI * _radius * _radius;
}
@override
String toString() {
return super.toString() + " Rayon : $_radius, Surface : $_surface";
}
}
Solution
class Batiment {
String adresse;
// Constructeur par défaut
Batiment() {
adresse = "Adresse par défaut";
}
// Constructeur avec adresse
Batiment.withAdresse(this.adresse);
// Accesseurs et mutateurs
String getAdresse() {
return adresse;
}
void setAdresse(String nouvelleAdresse) {
adresse = nouvelleAdresse;
}
// Méthode ToString
@override
String toString() {
return 'Batiment{adresse: $adresse}';
}
}
class Maison extends Batiment {
int nbPieces;
// Constructeur par défaut
Maison() : super() {
nbPieces = 0;
}
// Constructeur avec adresse et nombre de pièces
Maison.withAdresseNbPieces(String adresse, this.nbPieces) : super.withAdresse(adresse);
// Accesseurs et mutateurs pour nbPieces
int getNbPieces() {
return nbPieces;
}
void setNbPieces(int nouveauNbPieces) {
nbPieces = nouveauNbPieces;
}
// Méthode ToString
@override
String toString() {
return 'Maison{adresse: $adresse, nbPieces: $nbPieces}';
}
}
void main() {
// Test des classes Batiment et Maison
Batiment batiment1 = Batiment();
print(batiment1);
Batiment batiment2 = Batiment.withAdresse("123 Rue de la Test");
print(batiment2);
Maison maison1 = Maison();
print(maison1);
Maison maison2 = Maison.withAdresseNbPieces("456 Avenue du Test", 5);
print(maison2);
// Test des accesseurs et mutateurs
batiment1.setAdresse("789 Boulevard de l'Exemple");
print(batiment1.getAdresse());
maison1.setNbPieces(3);
print(maison1.getNbPieces());
}