Théorie 1.2.4: interface, classe abstraite #
-
On a vu que
extends
etimplements
peuvent spécifier un contrat:- une liste de méthodes qu’il faut implanter
-
P.ex. pour
extends
:
- P.ex. pour
implements
:
-
Vous avez déjà rempli ces contrats dans les tutoriels et les ateliers
-
Maintenant, pour créer vos propres contrats, il faut créer soit:
- une classe abstraite dans le cas de
extends
- une interface dans le cas de
implements
- une classe abstraite dans le cas de
Interface #
-
L’interface est le contrat le plus simple
-
Il s’agit exclusivement de signatures de méthodes publiques
-
L’interface ne contient jamais le code d’une méthode
-
P.ex. voici deux interfaces:
public interface Rouleur {
// public par défaut!
void rouler(double kilometres);
}
public interface Formateur {
String formater();
String formaterEnHtml();
}
- Pour implanter l’interface
Rouleur
, il faut obligatoirement implanter la méthoderouler
public class MonRouleur implements Rouleur {
@Override
public void rouler(double kilometres){
//public!
}
}
- Pour implanter l’interface
Formateur
, il faut obligatoirement implanter deux méthodes:
public class MonFormateur implements Formateur {
@Override
public String formater(){
//public!
return null;
}
@Override
public String formaterEnHtml(){
//public!
return null;
}
}
- NOTE: le contrat concerne uniquement la signature et non le code de la méthode
Classe abstraite #
-
La classe abstraite est plus flexible
-
Elle implante certaines méthodes:
//abstract!
public abstract class Atelier {
public boolean isAProviderMethod(Method method) {
return method.getName().startsWith("fournir");
}
public void valider() {
validateTestCases();
launchApp();
Validator.validate(this);
}
- Alors que d’autres sont abstraites et seulement la signature est spécifiée:
//abstract!
protected abstract void executer();
protected abstract boolean siExecutable();
- Au complet ça donne:
//abstract!
public abstract class Atelier {
public boolean isAProviderMethod(Method method) {
return method.getName().startsWith("fournir");
}
public void valider() {
validateTestCases();
launchApp();
Validator.validate(this);
}
//abstract!
protected abstract void executer();
protected abstract boolean siExecutable();
}
- Quand on hérite de
Atelier
il faut obligatoirement implanter deux méthodes:
//!=abstract
public class MonAtelier extends Atelier {
@Override
protected void executer(){
//!=abstract
}
@Override
protected boolean siExecutable(){
//!=abstract
return false;
}
}
- NOTE: une méthode abstraite peut être
protected
Impossible d’instancier une interface ou une classe abstraite #
-
On ne peut pas créer un objet à partir d’une interface ou d’une classe abstraite
-
P.ex. si on essaie d’instancier une classe abstraite:
- P.ex. si on essaie d’instancier une interface:
- Pour créer un objet qui remplit le contrat, il faut utiliser
extends
ouimplements
Quand utiliser une interface? #
-
Quand on veut faire la liste des méthodes publiques d’une classe
-
Typiquement, on utiliser une interface pour chaque thème:
rouler
,formater
,manger
-
Une classe peut implanter plusieurs interfaces (c-à-d plusieurs
implements
):
public class MonVehicule implements Rouleur, Formateur {
@Override
public void rouler(double kilometres){
}
@Override
public String formater(){
return null;
}
@Override
public String formaterEnHtml(){
return null;
}
}
Interface et polymorphisme #
-
Une interface est aussi une façon d’accéder à un comportement restreint d’un objet
-
P.ex:
public class Principal {
public static void main(String[] args){
Rouleur vehicule = new MonVehicule();
// OK
vehicule.rouler(10.0);
// ERREUR
System.out.println(vehicule.formater());
}
}
-
En utilisant la variable
Rouleur vehicule
(de typeRouleur
), on dit:- j’ai seulement besoin des méthodes spécifiées dans
Rouleur
- les autres méthodes de
Vehicule
ne seront pas accessibles
- j’ai seulement besoin des méthodes spécifiées dans
-
Notre code est alors plus général et plus lisible:
- on a rendu explicite le contrat qu’on utilise
- n’importe quel objet qui implante
Rouleur
est compatible avec notre code- (et non uniquement les objets de type
Vehicule
)
- (et non uniquement les objets de type
Quand utiliser une classe abtraite? #
-
Quand on veut obliger une sous-classe à redéfinir une méthode
-
Typiquement, cette méthode n’a pas de sens dans la classe parent
-
P.ex:
public abstract class Vehicule extends Object implements Rouleur, Formateur {
protected abstract double consommationLitresParKilometre();
protected abstract String nomVehicule();
protected abstract boolean siNomFeminin();
-
Aucune des méthodes ci-haut n’a de sens dans
Vehicule
- il faut un type de véhicule en particulier (
Auto
,Moto
) pour répondre
- il faut un type de véhicule en particulier (
-
Mais on veut utiliser ces méthodes dans
Vehicule
, p.ex:
private double litresEssenceConsomes() {
return totalKilometres * consommationLitresParKilometre();
}
-
Alors la classe abstraite force les sous-classes à avoir ces méthodes
-
C’est le contrat de la classe abstraite
Pourquoi ne pas toujours utiliser une classe abstraite? #
-
Parce que ce n’est pas permis en Java ;-)
-
Java ne supporte pas l’héritage multiple (c-à-d plusieurs
extends
)