Introduction
L’héritage et le polymorphisme sont des mécanismes très intéressants qui permettent de bien représenter les objets réels, de diminuer la complexité du code et qui permettent d’augmenter grandement la réutilisation de code et la facilité de maintenance d’un logiciel. Par contre, dans tous ces mécanismes, il manque un élément important.
En effet, dans une même catégorie d’objet, il est possible que tous les objets aient des mécaniques similaires communes, mais que leurs implémentations divergent plus ou moins légèrement d’un objet à l’autre.
Pour donner un exemple plus concret, on peut imaginer que tous les véhicules ont la capacité de se déplacer; mais la mécanique qui permet ce déplacement est très différente si on observe un bateau à voile ou une automobile.
En objet, c’est ce que permettent de représenter les méthodes abstraites.
Les méthodes abstraites
Il arrive que, lors du « design » d’une classe, il soit logique que tous les objets de ce type aient une certaine méthode, mais que l’implémentation de cette méthode puisse différer en fonction des descendants de cette classe. Dans ce cas, il est nécessaire de déclarer cette méthode dans la classe, sans fournir d’implémentation. La déclaration de cette méthode est appelée méthode abstraite.
Pour fournir un exemple, nous allons utiliser le « design » que nous avons développé durant les théories précédentes:
Ce « desing » est fonctionnel, mais nécessite d’effectuer des tests de type ainsi que du « cast » de type pour lancer le cri (aboyer et miauler) des différents animaux. Par exemple, voici le code que nous avons développé à ce sujet:
public void criAnimal(Animal aAnimal) {
if (aAnimal instanceof Chien) {
( (Chien)aAnimal).aboyer();
} else if (aAnimal instanceof Chat) {
( (Chat) aAnimal).miauler();
}
}
Le problème ici, c’est que chaque type enfant doit être géré individuellement; ce qui rend moins intéressant le principe de polymorphisme. Il suffit d’imaginer qu’il y a 20 classes enfants de Animal différentes pour voir que cette méthode deviendra trop complexe. De plus, à chaque fois qu’une nouvelle classe enfant de Animal est créée, il faut modifier du code dans chaque client de la classe afin d’ajouter la gestion du nouvel enfant.
Pour nous rapprocher de la solution, nous pourrions imaginer mettre toutes les méthodes de cri d’animaux avec le même nom. Comme ceci:
L’objectif serait de pouvoir seulement faire ce code:
public void criAnimal(Animal aAnimal) {
aAnimal.cri();
}
Par contre, ici, le code ne fonctionne pas parce que, même si Chien et Chat ont une méthode cri(), il n’est pas spécifié dans Animal que cette méthode cri() existe. Puisque le compilateur considère que cette variable est de type Animal (et non Chien et Chat), il faut que la classe Animal contienne cette méthode pour que le code ci-haut compile.
Ainsi, pour préciser au compilateur que la méthode existera toujours, dans tous les enfants de Animal, je vais déclarer la méthode cri() dans Animal, mais sans préciser d’implémentation. Les implémentations seront programmées dans les enfants. Voici le code (qui n’est pas encore final) de ce que ça aura l’air.
/**
* Représente tous les spécimens animal.
*
* @author Louis Marchand (prog@tioui.com)
* @version 0.1, mercredi mar 10, 2021 16:58:57 EST
*
* Distribué sous licence MIT.
*/
public class Animal {
...
public abstract void cri();
...
}
On nomme cette ligne de code méthode abstraite cri().
Les classes abstraites
Un autre problème survient en regardant le code précédent. Ce qu’il faut lire, c’est que tous les enfants de la classe Animal devront implémenter la méthode cri(), sinon, la compilation échouera. Par contre, qu’arrivera-t-il si je fais le code suivant:
Animal lAnimal = new Animal("Socrate", 3);
lAnimal.cri();
Jusqu’à maintenant, je pouvais effectivement créer directement un objet de type Animal. Par contre, ici, si j’effectue ce code, il est à se demander que donnera l’expression « lAnimal.cri() » puisque « lAnimal » n’est pas de type Chien ni de type Chat et qu’il n’y a aucune implémentation de la méthode « cri() » dans la classe Animal.
Puisque l’utilisation de méthode abstraite rend la classe d’une certaine manière impossible à instancier directement, nous allons utiliser un nouveau type de classe. Nous allons appeler ce type de classe classe abstraite. Voici les caractéristiques importantes des classes abstraites:
-
- elles représentent normalement une catégorie (ou un groupe) de classes (les classes enfants);
- elles représentent habituellement une idée et non un objet concret;
- elles sont les seules classes pouvant contenir une ou plusieurs méthodes abstraites;
- Il est impossible de créer une nouvelle instance de cette classe (on ne peut pas faire de « new » avec ce type).
Voici donc les classes Animal (abstraite), Chien, Chat et un exemple de programme.
Animal.java:
/**
* Représente tous les spécimens animal.
*
* @author Louis Marchand (prog@tioui.com)
* @version 0.1, mercredi mar 10, 2021 16:58:57 EST
*
* Distribué sous licence MIT.
*/
public abstract class Animal {
/**
* L'identificateur de l'Animal
*/
public String nom;
/**
* Retourne nom.
* @return nom
*/
public String getNom() {
return nom;
}
/**
* Assigne nom.
* @param aNom Nouvelle valeur de nom.
*/
public void setNom(String aNom) {
nom = aNom;
}
/**
* Le nombre d'années depuis la naissance de l'Animal
*/
public int age;
/**
* Retourne age.
* @return age
*/
public int getAge() {
return age;
}
/**
* Assigne age.
* @param aAge Nouvelle valeur de age.
*/
public void setAge(int aAge) {
age = aAge;
}
/**
* Le son qu'émet l'Animal
*/
public abstract void cri();
/**
* Constructeur de Animal
*
* @param aNom Valeur de nom
* @param aAge Valeur de age
*/
public Animal(String aNom, int aAge) {
nom = aNom;
age = aAge;
}
}
Chien.java:
/**
* Animal de race canine.
*
* @author Louis Marchand (prog@tioui.com)
* @version 0.1, mercredi mar 10, 2021 17:03:49 EST
*
* Distribué sous licence MIT.
*/
public class Chien extends Animal{
/**
* Le son qu'émet l'Animal
*/
public void cri() {
System.out.println("Wouf Wouf!");
}
/**
* Constructeur du Chien
*
* @param aNom Valeur de nom
* @param aAge Valeur de age
*/
public Chien(String aNom, int aAge) {
super(aNom, aAge);
}
}
Chat.java:
/**
* Animal de race féline.
*
* @author Louis Marchand (prog@tioui.com)
* @version 0.1, mercredi mar 10, 2021 17:03:49 EST
*
* Distribué sous licence MIT.
*/
public class Chat extends Animal{
/**
* Le son qu'émet l'Animal
*/
public void cri() {
System.out.println("Miaou!");
}
/**
* Constructeur du Chat
*
* @param aNom Valeur de nom
* @param aAge Valeur de age
*/
public Chat(String aNom, int aAge) {
super(aNom, aAge);
}
}
Programme.java
/**
* Programme principal de l'exemple des animaux.
*
* @author Louis Marchand (prog@tioui.com)
* @version 0.1, mercredi mar 10, 2021 17:14:16 EST
*
* Distribué sous licence MIT.
*/
public class Programme {
public void afficherInformation(Animal aAnimal) {
String typeAnimal = "de l'animal";
if (aAnimal instanceof Chien){
typeAnimal = "du chien";
} else if (aAnimal instanceof Chat) {
typeAnimal = "du chat";
}
System.out.println("L'age " + typeAnimal + " " + aAnimal.getNom() + " est " +
aAnimal.getAge());
}
/**
* Exécution du programme.
*
* @param aArguments Les paramêtres du programme.
*/
public static void main(String[] aArguments) {
Chien lChien = new Chien("Rex", 10);
Chat lChat = new Chat("Minou", 3);
Programme programme = new Programme();
programme.afficherInformation(lChien);
programme.afficherInformation(lChat);
System.out.print("Cri du chien: ");
lChien.cri();
System.out.print("Cri du chat: ");
lChat.cri();
}
}
Les méthodes et classes effectives
On appel méthode effective une méthode proposant une implémentation. En d’autres mots, une méthode qui n’est pas abstraite est dite effective.
De la même manière, on appel classe effective une classe qui n’est pas abstraite.
Diagramme de classe
Il est important de noter qu’une classe abstraite et une méthode abstraite sont indiquées en italique dans un diagramme de classe. Voici le diagramme de classe final de notre modèle d’Animal:
Auteur: Louis Marchand
Sauf pour les sections spécifiées autrement, ce travail est sous licence Creative Commons Attribution 4.0 International.