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 classe d’étendre plus d’une classe. Cette restriction existe en raison d’un problème connu sous le nom de problème du diamant.

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 illustre la règle de l’héritage simple de Java et montre comment créer malgré tout des conceptions flexibles dans cette contrainte.

Imagine que tu souhaites créer une enceinte intelligente qui combine les fonctionnalités d’un lecteur de musique et d’un assistant vocal. Comme Java n’autorise pas l’extension de plusieurs classes, tu devras concevoir soigneusement ta hiérarchie en utilisant l’héritage simple.

Tu vas créer quatre fichiers pour organiser ton code :

  • AudioDevice.java : crée la classe de base que partagent tous les appareils capables de lire de l’audio. Elle doit posséder :
    • un champ privé pour deviceName (String)
    • un constructeur qui accepte le nom de l’appareil
    • une méthode getDeviceName() qui renvoie le nom
    • une méthode playSound() qui affiche : [deviceName]: Playing audio
  • MusicPlayer.java : crée une classe qui étend AudioDevice et ajoute des fonctionnalités propres à la musique :
    • un champ privé pour currentSong (String)
    • un constructeur qui accepte le nom de l’appareil et utilise super(deviceName)
    • une méthode setSong(String song) qui définit la chanson actuelle
    • redéfinis playSound() pour afficher : [deviceName]: Now playing - [currentSong]
  • SmartSpeaker.java : crée une classe qui étend MusicPlayer (et non à la fois MusicPlayer et une classe VoiceAssistant : cela constituerait un héritage multiple !). L’enceinte intelligente s’appuie sur le lecteur de musique en ajoutant des fonctionnalités vocales :
    • un champ privé pour assistantName (String)
    • un constructeur qui accepte 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 : illustre ta chaîne d’héritage multiniveau. Tu recevras trois entrées : un nom d’appareil (String), un nom d’assistant (String) et un nom de chanson (String). Crée une instance de SmartSpeaker, définis une chanson, puis appelle ces méthodes dans l’ordre :
    • getFullInfo()
    • playSound()
    • voiceCommand("skip to next")

Tu recevras trois entrées : le nom de l’appareil, le nom de l’assistant et le nom de la chanson.

Remarque comment SmartSpeaker acquiert des fonctionnalités musicales en étendant MusicPlayer au sein d’une chaîne (AudioDevice -> MusicPlayer -> SmartSpeaker), plutôt qu’en essayant d’étendre plusieurs classes sans lien. C’est l’approche de Java pour conserver un héritage propre et dépourvu d’ambiguïté !

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

Entraînez-vous par vous-même : Compilateur Java en ligne