Maîtrise du Développement Java
POO Avancée
Au-delà des bases : l'abstraction
En programmation orientée objet, vous savez déjà comment créer des classes pour modéliser des objets du monde réel. Mais que se passe-t-il lorsque vous avez un groupe de classes similaires qui partagent une structure commune, mais dont les détails diffèrent ? C'est là que les classes abstraites entrent en jeu.
Une classe abstraite est comme un modèle incomplet. Elle définit une structure et un comportement communs que ses sous-classes doivent suivre, mais elle ne peut pas être instanciée directement. Pensez-y comme à un plan pour une "Voiture". Le plan peut spécifier qu'une voiture doit avoir des roues et un moteur, mais il ne définit pas le type de moteur ou la taille des roues. Ce sont les modèles spécifiques, comme une "VoitureDeSport" ou un "SUV", qui fourniront ces détails concrets.
Une classe abstraite sert de base commune, garantissant que toutes les classes dérivées partagent une structure et des méthodes essentielles.
Dans une classe abstraite, vous pouvez avoir des méthodes avec une implémentation complète, ainsi que des méthodes abstraites, qui sont de simples déclarations sans corps. Toute classe qui hérite de la classe abstraite est obligée de fournir une implémentation pour toutes les méthodes abstraites. Cela garantit une certaine cohérence entre toutes les sous-classes.
// Classe abstraite : un modèle pour tous les animaux
abstract class Animal {
// Méthode concrète, partagée par toutes les sous-classes
public void respirer() {
System.out.println("Cet animal respire.");
}
// Méthode abstraite : chaque sous-classe DOIT l'implémenter
public abstract void faireUnSon();
}
// Classe concrète qui hérite d'Animal
class Chien extends Animal {
// Implémentation obligatoire de la méthode abstraite
@Override
public void faireUnSon() {
System.out.println("Woof !");
}
}
// Utilisation
Chien monChien = new Chien();
monChien.respirer(); // Affiche "Cet animal respire."
monChien.faireUnSon(); // Affiche "Woof !"
// new Animal(); // Erreur de compilation ! On ne peut pas instancier une classe abstraite.
Interfaces : contrats et flexibilité
Si les classes abstraites concernent ce qu'un objet est, les interfaces concernent ce qu'un objet peut faire. Une interface est un contrat. Elle spécifie un ensemble de méthodes qu'une classe doit implémenter, sans se soucier de la manière dont elle le fait. Une classe peut implémenter plusieurs interfaces, ce qui lui permet d'adopter plusieurs "rôles". Par exemple, une classe Oiseau pourrait implémenter les interfaces Volant et Chantant.
Depuis Java 8, les interfaces sont devenues encore plus puissantes. Elles peuvent contenir des méthodes par défaut (default methods), qui fournissent une implémentation qu'une classe peut utiliser ou surcharger. Elles peuvent également avoir des méthodes statiques, qui sont des fonctions utilitaires liées à l'interface elle-même.
Une catégorie particulière d'interface est l', qui ne contient qu'une seule méthode abstraite. Ces interfaces sont la pierre angulaire des expressions lambda en Java, offrant un moyen concis d'exprimer des instances de classes à méthode unique.
// Interface définissant une capacité
@FunctionalInterface
interface Volant {
void decoller(); // Méthode abstraite unique
// Méthode par défaut, avec une implémentation
default void atterrir() {
System.out.println("Atterrissage en douceur.");
}
// Méthode statique, une fonction utilitaire
static String description() {
return "Cette interface concerne les objets volants.";
}
}
class Avion implements Volant {
@Override
public void decoller() {
System.out.println("L'avion décolle de la piste.");
}
}
// Utilisation
Avion boeing747 = new Avion();
boeing747.decoller();
boeing747.atterrir(); // Utilise la méthode par défaut
System.out.println(Volant.description()); // Appelle la méthode statique