Interfaces vs. Classes Abstraites
Dans le paradigme de la programmation orientée objet (POO) en Java, les interfaces et les classes abstraites fournissent toutes deux des mécanismes pour atteindre l'abstraction et le polymorphisme. Bien qu'elles partagent certaines similitudes, leurs objectifs principaux, leurs capacités et leurs cas d'utilisation diffèrent significativement.
Interfaces
Une interface en Java est un modèle de classe. Elle peut avoir des champs static final
(constantes) et des méthodes abstraites. À partir de Java 8, les interfaces peuvent également avoir des méthodes default
et static
. À partir de Java 9, les méthodes private
sont également autorisées.
Caractéristiques clés :
- Abstraction à 100 % : Historiquement, toutes les méthodes d'une interface étaient implicitement
public abstract
et n'avaient pas d'implémentation. - Champs : Ne peuvent déclarer que des champs
public static final
(constantes). Ceux-ci sont implicitementpublic static final
. - Méthodes :
- Méthodes
public abstract
(implicitement). - Méthodes
default
(à partir de Java 8) fournissent une implémentation par défaut que les classes implémentantes peuvent surcharger. - Méthodes
static
(à partir de Java 8) sont des méthodes utilitaires liées à l'interface elle-même, et non à ses objets implémentants. - Méthodes
private
etprivate static
(à partir de Java 9) pour prendre en charge les méthodesdefault
etstatic
au sein de l'interface.
- Méthodes
- Constructeurs : Ne peuvent pas avoir de constructeurs.
- Héritage : Une classe
implémente
une interface. Une classe peut implémenter plusieurs interfaces (héritage multiple de type). Une interface peutétendre
plusieurs autres interfaces. - Modificateurs d'accès : Tous les membres sont implicitement
public
(sauf les méthodes privées).
Cas d'utilisation :
- Définir des contrats : Les interfaces sont idéales pour définir des contrats auxquels les classes doivent adhérer. Toute classe implémentant une interface garantit de fournir des implémentations pour ses méthodes abstraites.
- Réaliser l'héritage multiple de type : Puisqu'une classe peut implémenter plusieurs interfaces, elle peut acquérir des comportements de plusieurs sources, contournant la limitation de l'héritage simple de Java pour les classes.
- Couplage faible : Favorise un couplage faible en permettant aux classes d'interagir sur la base d'interfaces définies plutôt que d'implémentations concrètes.
- Mécanismes de rappel (Callback) : Souvent utilisées pour définir des méthodes de rappel.
Exemple :
interface Shape {
double PI = 3.14159; // public static final par défaut
double calculateArea(); // public abstract par défaut
double calculatePerimeter();
default void display() { // Méthode par défaut
System.out.println("Ceci est une forme.");
}
}
class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return PI * radius * radius;
}
@Override
public double calculatePerimeter() {
return 2 * PI * radius;
}
}
Classes Abstraites
Une classe abstraite est une classe qui ne peut pas être instanciée seule et peut contenir des méthodes abstraites (méthodes sans implémentation) ainsi que des méthodes concrètes (implémentées). Elle sert de classe de base pour d'autres classes, fournissant des fonctionnalités communes et définissant un modèle pour les sous-classes.
Caractéristiques clés :
- Abstraction partielle : Peut avoir à la fois des méthodes abstraites et des méthodes concrètes. Elle peut être abstraite à 0 % (aucune méthode abstraite mais toujours déclarée
abstract
) ou jusqu'à 100 % abstraite (toutes les méthodes sont abstraites). - Champs : Peut avoir tout type de champs (statiques, non statiques, finaux, non finaux) avec n'importe quel modificateur d'accès (
public
,protected
,private
, par défaut). - Méthodes : Peut avoir des méthodes abstraites (déclarées avec le mot-clé
abstract
) et des méthodes concrètes. - Constructeurs : Peut avoir des constructeurs. Ces constructeurs sont appelés lorsqu'une sous-classe concrète est instanciée.
- Héritage : Une classe
étend
une classe abstraite. Une classe ne peut étendre qu'une seule classe abstraite (héritage simple). Une classe abstraite peutétendre
une autre classe ou classe abstraite et peutimplémenter
des interfaces. - Modificateurs d'accès : Les membres peuvent avoir n'importe quel modificateur d'accès.
- Méthodes
final
: Une classe abstraite peut avoir des méthodesfinal
, qui ne peuvent pas être surchargées par les sous-classes.
Cas d'utilisation :
- Réutilisabilité du code : Fournit une base commune pour les classes apparentées, permettant aux sous-classes de partager des méthodes et des champs implémentés en commun.
- Modèle de méthode de gabarit (Template Method Pattern) : Souvent utilisé pour implémenter le modèle de conception de méthode de gabarit, où un squelette d'algorithme est défini dans la classe abstraite, et les étapes concrètes sont laissées aux sous-classes pour implémentation.
- Hiérarchie d'objets liés : Le mieux adapté lorsqu'il existe une relation "est un" et que vous souhaitez fournir un état et un comportement communs à un groupe d'objets étroitement liés.
- Contrôle de version : Plus facile à faire évoluer que les interfaces sans casser les implémentations existantes, car vous pouvez ajouter de nouvelles méthodes concrètes sans forcer les sous-classes à les implémenter.
Exemple :
abstract class Vehicle {
String brand;
int year;
public Vehicle(String brand, int year) { // Constructeur
this.brand = brand;
this.year = year;
}
public void displayInfo() { // Méthode concrète
System.out.println("Marque : " + brand + ", Année : " + year);
}
public abstract void start(); // Méthode abstraite
public abstract void stop();
}
class Car extends Vehicle {
public Car(String brand, int year) {
super(brand, year);
}
@Override
public void start() {
System.out.println("La voiture démarre avec une clé.");
}
@Override
public void stop() {
System.out.println("La voiture s'arrête en appuyant sur le frein.");
}
}
Principales différences résumées
Caractéristique | Interface | Classe Abstraite |
---|---|---|
Type de membres | Seulement champs public static final . Méthodes abstraites, par défaut, statiques et privées. | Tout type de champs (statiques, non statiques, finaux, non finaux) avec n'importe quel modificateur d'accès. Méthodes abstraites et concrètes. |
Abstraction | Historiquement, 100 % abstraite. Maintenant, peut avoir des méthodes concrètes default et static . | Peut être abstraite de 0 % à 100 % (peut avoir zéro ou plusieurs méthodes abstraites). |
Méthodes | Les méthodes abstraites sont implicitement public abstract . Peut avoir des méthodes default , static , private . | Les méthodes abstraites sont explicitement abstract . Peut avoir des méthodes concrètes avec n'importe quel modificateur d'accès. |
Constructeurs | Ne peut pas avoir de constructeurs. | Peut avoir des constructeurs. |
Héritage | Une classe implémente des interfaces. Prend en charge l'héritage multiple de type. Une interface étend d'autres interfaces. | Une classe étend une classe abstraite. Prend en charge l'héritage simple uniquement. |
"Est un" vs "Peut faire" | Définit une capacité "peut faire" ou un contrat. | Définit une relation "est un" ou une base commune. |
Mots-clés | interface , implements , extends | abstract , class , extends , implements |
Méthodes Finales | Les méthodes ne peuvent pas être final (mais les méthodes default et static ne sont implicitement pas destinées à être surchargées directement par les sous-classes). | Peut avoir des méthodes final , qui ne peuvent pas être surchargées. |
Quand choisir l'un ou l'autre
-
Choisissez une Interface quand :
- Vous voulez définir un contrat pour ce que les classes peuvent faire, indépendamment de leur position dans la hiérarchie d'héritage.
- Vous avez besoin de réaliser l'héritage multiple de type.
- Vous voulez promouvoir un couplage faible entre les composants.
- Vous définissez une API ou un ensemble de comportements que des classes non liées pourraient implémenter.
-
Choisissez une Classe Abstraite quand :
- Vous voulez fournir une implémentation de base commune pour des classes apparentées, partageant du code et de l'état.
- Vous avez des méthodes qui devraient être implémentées par les sous-classes, mais aussi des méthodes avec une implémentation par défaut qui peuvent être héritées.
- Vous avez besoin de définir des champs (variables) communs que les sous-classes partageront.
- Vous voulez imposer une hiérarchie spécifique pour un ensemble de classes.
- Vous avez besoin de fournir des constructeurs pour les sous-classes.
En substance, les interfaces définissent ce qu'un objet peut faire (son contrat/comportement), tandis que les classes abstraites définissent ce qu'un objet est (son type et son implémentation partagée). Souvent, les conceptions complexes peuvent utiliser une combinaison des deux pour réaliser des architectures robustes et extensibles.