Les éléments abstraits
Les classes abstraites
Une classe peut être déclarée abstraite. Cela empêche de créer des instances de cette classe. Cela peut sembler surprenant d’écrire une classe si aucune instance de cette classe ne peut être créée, pourtant ces classes peuvent être très utiles. Il est, par exemple, possible de créer une classe regroupant tout ce qui est commun à deux classes assez semblables pour en faire leur classe parent et ainsi éviter de dupliquer du code.
Par exemple, supposons que pour la bataille navale, deux types de joueurs puissent s’affronter : soit des joueurs humains, soit des joueurs ordinateurs. Ces deux types de joueurs auront un certain nombre d’attributs communs (un nom, un champ de tir, des bateaux…) et des méthodes communes (ajouter un bateau à sa flottille en vérifiant que cet ajout ne crée pas de superposition, tester l’effet d’un tir sur sa flottille…). Il est donc judicieux de créer une classe Joueur contenant tous ces éléments communs et de faire hériter de celle-ci deux classes : une classe JoueurHumain et une autre JoueurOrdinateur.
Dans cet exemple, nous avons besoin de créer des instances de JoueurHumain et de JoueurOrdinateur, par contre nous ne souhaitons pas qu’il soit possible de créer d’instance de la classe Joueur. Celle-ci n’a été créée que pour mutualiser des éléments. Cette classe est donc déclarée abstraite.
Pour déclarer une classe abstraite, il faut utiliser le mot-clé abstraite :
Classe abstraite NomDeLaClasse
En Java, le caractère abstrait d’une classe est indiqué par le mot-clé abstract :
public abstract class NomDeLaClasse {
...
}
Une classe abstraite peut posséder tout ce que possède une classe concrète (c’est-à-dire non abstraite) : attributs d’instance ou de classe, constantes, méthodes d’instance ou de classe et même des constructeurs. Bien qu’il soit impossible de faire appel à ces constructeurs pour créer des instances, ces constructeurs peuvent être appelés par les constructeurs des classes héritant de celle-ci.
Voici par exemple...
Les méthodes abstraites
1. La déclaration de méthodes abstraites
Au sein d’une classe abstraite, il est possible de créer des méthodes abstraites. Une méthode abstraite est une méthode qui ne possède pas de corps. Il n’y a que sa signature qui est indiquée. Il n’y a pas de déclarations de variables ou de constantes, ni d’instructions, ni même les mots-clés Début et Fin.
Syntaxe pour une procédure :
Procédure abstraite nomDeLaProcedure(listeDesParamètres)
Syntaxe pour une fonction :
Fonction abstraite nomDeLaFonction(listeDesOaramètres) Retourne
typeDeRetour
Le fait de déclarer une méthode abstraite dans une classe impose que celle-ci soit déclarée abstraite.
Le fait de déclarer une méthode abstraite au sein d’une classe abstraite va obliger les classes concrètes qui en héritent à avoir une définition concrète de cette méthode, c’est-à-dire avec un corps contenant des instructions. L’intérêt des méthodes abstraites est qu’elles permettent de s’assurer de la présence de certaines méthodes dans les classes concrètes qui en héritent.
Étant donné qu’il n’est possible de créer des instances que de classes concrètes et que celles-ci ont forcément donné un corps pour toutes les méthodes abstraites héritées, l’appel à une méthode sur une instance exécute donc bien une méthode concrète.
Dans la classe Joueur, deux méthodes abstraites peuvent être ajoutées afin d’obliger toutes les classes concrètes à avoir ces méthodes et à leur donner un corps.
Exemple :
Classe abstraite Joueur
Attribut nom : texte
Attribut champDeTir : Grille
Attribut bateaux : Bateau[5]
Attribut nbBateaux : entier
Attribut nbBateauxCoules : entier
Attribut adversaire : Joueur
Méthodes
Constructeur()
Début
champDeTir <- nouveau Grille()
nbBateaux <- 0
nbBateauxCoules <- 0
Fin ...
Les interfaces
1. La déclaration d’une interface
Une interface est un peu comme une classe abstraite, mais en version minimaliste. Une interface peut contenir des méthodes abstraites, mais ne peut plus avoir de méthodes d’instance concrètes, de constructeurs ou d’attributs. Une interface permet donc de définir un ensemble de méthodes à implémenter.
Cela établit ainsi un contrat que certaines classes peuvent s’engager à respecter.
Pour définir une interface, il faut utiliser la syntaxe suivante :
Interface NomDeLInterface
# définition de constantes
# définition de méthodes abstraites
FInterface
Par exemple, il est possible de définir une interface Jouable contenant deux méthodes abstraites jouer() et getNomDuJeu() :
Interface Jouable
Procédure abstraite jouer()
Fonction abstraite getNomDuJeu() Retourne texte
FInterface
En Java, pour définir une interface, tout comme pour une classe, il faut créer un fichier portant le même nom que l’interface dans un dossier respectant l’arborescence du nom du package. Voici la syntaxe à utiliser :
visibilité interface NomInterface {
// définition de constantes
// définition de méthodes abstraites
}
La visibilité d’une interface est soit publique, soit restreinte au package.
Dans une interface, des constantes peuvent être définies. Celles-ci sont nécessairement publiques. Comme aucun attribut n’est autorisé dans une interface, les mots-clés public static final sont implicites, ils peuvent donc être omis.
Pour les méthodes, il en est de même : elles sont nécessairement publiques et abstraites. Les mots-clés public abstract sont donc également implicites et facultatifs.
Voici, par exemple, l’interface Jouable codée en Java :
package fr.eni.jeux;
public interface Jouable {
void jouer();
String getNomDuJeu();
}
2. L’implémentation d’une interface
Une classe implémente une interface lorsqu’elle s’engage...
Exercices
1. La location de cycles
L’objectif est de créer un programme permettant à un loueur de cycles d’afficher les modèles proposés à la location et les tarifs pratiqués.
Des vélos, des gyropodes et des gyroroues sont proposés à la location. Pour chacun, il est nécessaire de connaître sa marque, son modèle ainsi que sa date d’achat. Les vélos sont équipés d’un système de changement de vitesse. Certains possèdent plus de vitesses que d’autres. Les gyropodes et les gyroroues ont une certaine autonomie en kilomètres. En raison de son guidon, le gyropode nécessite que son pilote ait une taille minimale.
Vous pouvez supposer que vous disposez d’une classe LocalDate permettant de gérer la date d’achat.
a. Les classes et leurs attributs
Définir les classes nécessaires pour représenter les différents cycles proposés à la location. Indiquer les différents attributs de ces dernières et le caractère abstrait éventuel de certaines classes.
b. Les méthodes
Il est nécessaire de connaître le tarif de location de n’importe quel cycle.
cycle |
tarif de location à l’heure |
vélo |
4 € 90 |
gyroroue |
18 € 90 |
gyropode |
29 € 90 |
Ajouter aux classes précédentes les méthodes...
Solutions des exercices
1. La location de cycles
a. Les classes et leurs attributs
Les éléments communs à tous les types de cycles ont été regroupés au sein d’une classe abstraite Cycle. Les gyropodes et les gyroroues ont en commun l’autonomie de leur moteur. Une sous-catégorie de cycle a donc été créée : les cycles électriques, représentés par la classe abstraite CycleElectrique. Enfin, les éléments spécifiques à un type de cycle particulier sont positionnés dans la classe correspondante.
b. Les méthodes
La méthode abstraite getTarifLocationHeure() de la classe Cycle permet de s’assurer que toutes les classes concrètes héritant de celle-ci possèdent une implémentation concrète de cette méthode. Cette méthode est définie dans les classes Velo, Gyroroue et Gyropode. Elle n’est par contre pas définie dans la classe CycleElectrique, car celle-ci étant abstraite, elle n’a pas l’obligation de le faire.
c. Le code
Classe abstraite Cycle
Attribut dateAchat : LocalDate
Attribut marque : texte
Attribut modele : texte
Méthodes
Constructeur(dateAchat : LocalDate, marque : texte, modele : texte)
Début
instance.dateAchat <- dateAchat
instance.marque <- marque
instance.modele <- modele
Fin
Fonction age() Retourne entier
Début
Retourner instance.dateAchat.getNbAnnesPassees()
Fin
Fonction abstraite getTarifLocationHeure() Retourne réel
Fonction toString() Retourne texte
Variable age : entier <- age()
Début
Retourner instance.marque & " " & instance.modele & " (" & age &
"an" & age>1?"s":"" & ")"
Fin
FClasse
Classe Velo HériteDe Cycle
Attribut nbVitesse...