Interface en Java et C#

Introduction

Il est important de comprendre que la théorie présentée ici n’est pas une notion de programmation orientée objet, mais bien une notion propre à certains langages comme Java et C#. Afin de permettre une syntaxe orientée objet simple, les concepteurs de ces langages ont décidé de ne pas supporter l’héritage multiple.

En effet, le fait de pouvoir hériter de plusieurs classes (ce que nous nommons héritages multiples) peut causer des conflits dans les méthodes et attributs des différentes classes enfants.

Par contre, comme nous l’avons vu précédemment, autre que permettre le « desing objet », l’héritage permet, entre autres, deux avantages majeurs:

  • la généralisation des attributs et des méthodes, qui permettre de diminuer la duplication de code dans les classes enfants en déplaçant les méthodes et attributs dans un parent commun
  • le polymorphisme, qui permet de diminuer la duplication de code dans le client des classes en généralisant les appels de méthodes.

Il est à noter que l’analyse des problématiques liées à l’héritage multiple a montré que cette dernière ne pose problème qu’au niveau des méthodes et attributs généralisés lors de l’héritage et non pour le polymorphisme.

Les interfaces sont donc une mécanique utilisée dans certains langages permettant d’effectuer du polymorphisme, sans avoir à gérer les conflits causés par l’héritage.

Qu’est-ce qu’une interface en Java/C#

En Java et C#, on appelle interface une liste de définition de méthodes qu’une classe doit fournir à ses clients (méthode publique). D’une manière similaire, une interface est équivalente à une classe abstraite ne contenant que des méthodes abstraites (aucun attribut ni méthode effective ou implémentée).

Lorsqu’une classe « hérite » d’une interface, on dit que cette classe implémente une interface. On utilise ce terme pour s’assurer de ne pas confondre l’arbre d’héritage et la structure d’interface.

À quoi sert une interface en Java/C#

On voit que l’interface ne peut pas être utilisée afin d’encapsuler du code (méthodes) ou des données (attribut), comme peuvent le faire des classes. On peut donc se demander à quoi peut servir une interface.

L’avantage d’une interface par rapport à une classe est que (en Java et C#) est qu’il est impossible d’hériter de plus qu’une seule classe (ce qu’on appelle héritage simple). Par contre, malgré certaines problématiques causées par l’héritage multiple (que nous étudierons dans le cours de programmation orientée objet 2), ce type d’héritage a plusieurs avantages majeurs (diminution de la duplication de code, augmentation de la réutilisation de code, facilité de maintenance, polymorphisme, etc.) L’interface permet aux langages Java et C# d’avoir l’avantage du polymorphisme de l’héritage multiple, sans avoir à gérer les inconvénients de l’héritage multiple.

Exemple

L’utilisation de l’héritage multiple est variée, mais je peux tout de même vous montrer un exemple où ça pourrait s’appliquer.

Supposons que, dans notre système, nous avons la structure d’héritage suivante:

De plus, dans le même système, nous avons la structure suivante:

Supposons que nous voulons ajouter un nouvel Animal qui peut également être utilisé comme véhicule. Quelque chose comme ceci:

Nous voyons que ce « design » est impossible en Java et C# puisque ces langages ne gèrent pas l’héritage multiple et que le Cheval hérite de deux classes différentes. Pour régler cette problématique, nous pouvons utiliser un « design » avec interface. Par exemple:

Voici le code de l’interface « Pilotable » et « Cheval ». Au niveau où vous êtes rendu, vous devriez être capable de programmer vous-même les autres classes.

L’interface Pilotable:

/**
 * Interface commune aux objets qui peuvent être pilotés.
 * 
 * @author Louis Marchand (prog@tioui.com)
 * @version 0.1, lundi avr 05, 2021 17:13:42 EDT
 * 
 * Distribué sous licence MIT.
 */

public interface Pilotable {

    /**
     * Embarquement dans l'objet Pilotable.
     */
	public void embarquer();

    /**
     * Arrête d'avancer.
     *
     * @see #avancer
     */
    public void arreter();

    /**
     * L'objet pilotable commence à avancer.
     *
     * @see #arreter
     */
    public void avancer();
}

La classe Cheval:

/**
 * Classe représentant un Animal de race chevaline.
 * 
 * @author Louis Marchand (prog@tioui.com)
 * @version 0.1, lundi avr 05, 2021 17:09:37 EDT
 * 
 * Distribué sous licence MIT.
 */

public class Cheval extends Animal implements Pilotable{
	
    /**
     * Le son qu'émet l'Animal
     */
    public void cri() {
        System.out.println("Hiiiiii");
    }

    /**
     * Arrête d'avancer
     *
     * @see #avancer
     **/
    public void arreter() {
        System.out.println("Arrête de marcher.");    
    }

    /**
     * Embarquement sur le Cheval
     */
	public void embarquer() {
        System.out.println("Embarquement sur le cheval.");
    }

    /**
     * Constructeur du Cheval
     *
     * @param aNom Valeur de nom
     * @param aAge Valeur de age
     */
    public Cheval(String aNom, int aAge) {
        super(aNom, aAge);
    }
}

Voici maintenant un exemple de polymorphisme qui utilise cet interface:

public void demarrerTransport(Pilotable aPilotable) {
    aPilotable.embarquer();
    aPilotable.avancer();
}

On pourrait utiliser cette méthode comme ceci:

Cheval lCheval = new Cheval("Blacky", 10);
Automobile lAutomobile = new Automobile();
demarrerTransport(lCheval);
demarrerTransport(lAutomobile);

Particularité de Java

Depuis les dernières versions de Java, il est possible de mettre du code de routines à l’intérieur d’une interface. De cette manière, nous pouvons aller chercher certains autres avantages de l’héritage multiple, comme l’encapsulation de code.

Malheureusement, puisque le langage Java n’a pas été créé avec l’héritage multiple en tête, le code pouvant être placé dans une interface est assez limité. Des exemples de limitations sont:

    • Impossibilité de placer des attributs dans l’interface;
    • Ne pouvant pas accéder aux attributs des classes, les routines des interfaces sont similaires à des routines statiques;
    • Aucune gestion de conflit (si deux interfaces possèdent chacune une routine avec la même signature);
    • etc.

Retour

 


Auteur: Louis Marchand
Creative Commons License
Sauf pour les sections spécifiées autrement, ce travail est sous licence Creative Commons Attribution 4.0 International.