Menu
Coddy logo textTech

Pourquoi pas d'héritage multiple de classes

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 26 sur 87.

Java empêche délibérément une class d'étendre plus d'une class. Cette restriction existe en raison d'un problème connu sous le nom de Diamond Problem.

Imaginez si Java autorisait l'héritage multiple. Considérez ce scénario hypothétique :

// Ce code n'est PAS valide en Java
public class A {
    public void greet() {
        System.out.println("Hello from A");
    }
}

public class B extends A {
    @Override
    public void greet() {
        System.out.println("Hello from B");
    }
}

public class C extends A {
    @Override
    public void greet() {
        System.out.println("Hello from C");
    }
}

// PAS autorisé en Java !
public class D extends B, C { }

Si vous appeliez greet() sur un objet D, quelle version devrait s'exécuter ? Celle de B ou de C ? Cette ambiguïté est le problème du diamant (Diamond Problem), nommé d'après la forme de diamant formée par le diagramme d'héritage.

La solution de Java est simple : n'autoriser que l'héritage simple de classes. Cependant, Java propose une alternative. Une classe peut implémenter plusieurs interfaces, que vous découvrirez dans un prochain chapitre.

Les interfaces résolvent le problème du diamant différemment et vous offrent de la flexibilité sans l'ambiguïté.

// Ceci EST valide en Java
public class Dog extends Animal implements Runnable, Comparable<Dog> {
    // Peut implémenter plusieurs interfaces
}

Ce choix de conception maintient le modèle d'héritage de Java propre et prévisible, tout en permettant une réutilisation puissante du code via des interfaces.

challenge icon

Défi

Facile

Construisons un système de lecteur de musique qui démontre la règle d'héritage simple de Java et montre comment vous pouvez toujours concevoir des designs flexibles malgré cette contrainte.

Imaginez que vous souhaitiez créer une enceinte connectée qui combine les fonctionnalités d'un lecteur de musique et d'un assistant vocal. Comme Java ne permet pas d'étendre plusieurs classes, vous devrez concevoir votre hiérarchie avec soin en utilisant l'héritage simple.

Vous allez créer quatre fichiers pour organiser votre code :

  • AudioDevice.java : Créez la classe de base que tous les appareils de lecture audio partagent. Elle doit avoir :
    • Un champ privé pour deviceName (String)
    • Un constructeur qui accepte le nom de l'appareil
    • Une méthode getDeviceName() qui retourne le nom
    • Une méthode playSound() qui affiche : [deviceName]: Playing audio
  • MusicPlayer.java : Créez une classe qui étend AudioDevice et ajoute des fonctionnalités spécifiques à la musique :
    • Un champ privé pour currentSong (String)
    • Un constructeur qui prend le nom de l'appareil et utilise super(deviceName)
    • Une méthode setSong(String song) qui définit la chanson actuelle
    • Surchargez playSound() pour afficher : [deviceName]: Now playing - [currentSong]
  • SmartSpeaker.java : Créez une classe qui étend MusicPlayer (et non à la fois MusicPlayer et une classe VoiceAssistant - cela serait de l'héritage multiple !). L'enceinte connectée s'appuie sur le lecteur de musique en ajoutant des fonctionnalités vocales :
    • Un champ privé pour assistantName (String)
    • Un constructeur qui prend le nom de l'appareil et le nom de l'assistant, en utilisant super(deviceName)
    • Une méthode voiceCommand(String command) qui affiche : [assistantName]: Processing "[command]"
    • Une méthode getFullInfo() qui affiche : [deviceName] with [assistantName] assistant
  • Main.java : Démontrez votre chaîne d'héritage multiniveau. Vous recevrez trois entrées : un nom d'appareil (String), un nom d'assistant (String) et un nom de chanson (String). Créez un SmartSpeaker, définissez une chanson, puis appelez ces méthodes dans l'ordre :
    • getFullInfo()
    • playSound()
    • voiceCommand("skip to next")

Vous recevrez trois entrées : le nom de l'appareil, le nom de l'assistant et le nom de la chanson.

Remarquez comment SmartSpeaker acquiert des capacités musicales en étendant MusicPlayer dans une chaîne (AudioDevice -> MusicPlayer -> SmartSpeaker), plutôt que d'essayer d'étendre plusieurs classes non liées. C'est l'approche de Java pour garder l'héritage propre et sans ambiguïté !

Aide-mémoire

Java n'autorise que l'héritage simple - une classe ne peut étendre qu'une seule autre classe. Cela évite le problème du diamant (Diamond Problem), où une ambiguïté survient si une classe pouvait hériter de la même méthode de plusieurs classes parentes.

// NON autorisé en Java - héritage multiple
public class D extends B, C { } // ERREUR !

Cependant, Java permet à une classe d'implémenter plusieurs interfaces comme alternative :

// Valide en Java
public class Dog extends Animal implements Runnable, Comparable<Dog> {
    // Peut étendre une classe et implémenter plusieurs interfaces
}

Java prend en charge l'héritage multiniveau - la création de chaînes d'héritage :

public class AudioDevice { }

public class MusicPlayer extends AudioDevice { }

public class SmartSpeaker extends MusicPlayer { }
// SmartSpeaker hérite à la fois de MusicPlayer et d'AudioDevice

Essayez vous-même

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lire les entrées
        String deviceName = scanner.nextLine();
        String assistantName = scanner.nextLine();
        String songName = scanner.nextLine();
        
        // TODO: Créer un SmartSpeaker avec deviceName et assistantName
        
        // TODO: Définir la chanson en utilisant setSong()
        
        // TODO: Appeler getFullInfo()
        
        // TODO: Appeler playSound()
        
        // TODO: Appeler voiceCommand("skip to next")
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet