Les interfaces 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#.

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 méthode à 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;
    • Aucune gestion de conflit (si deux interfaces possèdent chacune une méthode avec la même signature);
    • etc.

À propos de Eiffel

Puisque Eiffel est un langage de programmation orienté objet permettant l’héritage multiple, il n’est pas nécessaire de recourir aux interfaces. Il suffit d’hériter directement des classes que nous désirons. Nous pouvons donc programmer sans problème la structure suivante en Eiffel.

Voici cet exemple dans le langage Eiffel.

Classe ANIMAL:

note
	description: "Un animal dans le programme d'animalerie."
	auteur: "Louis Marchand"
	date: "Mercredi, 25 Août 2021 19:29:24 +0000"
	revision: "0.1"

deferred class
	ANIMAL

feature {NONE} -- Initialisation

	make(a_nom:STRING; a_age:INTEGER)
			-- Initialisation de `Current' assignant `a_nom' à `nom'
			-- et `a_age' à `age'
		do
			set_nom(a_nom)
			set_age(a_age)
		end

feature -- Accès

	nom:STRING
			-- L'identificateur texte de `Current'

	age:INTEGER
			-- Le nombre d'année depuis la naisance de `Current'

	set_nom(a_nom:STRING)
			-- Assigne `a_nom' à `nom'
		do
			nom := a_nom
		end

	set_age(a_age:INTEGER)
			-- Assigne `a_age' à `age'
		do
			age := a_age
		end

	cri
			-- Le bruit que fait `Current'
		deferred
		end

	avancer
			-- `Current' se déplace
		do
			print("L'animal se met à avancer.%N")
		end
end

Classe VEHICULE:

note
	description: "Représente un véhicule dans le programme l'animalerie."
	auteur: "Louis Marchand"
	date: "Mercredi, 25 Août 2021 19:29:24 +0000"
	revision: "0.1"

deferred class
	VEHICULE

feature -- Accès

	embarquer
			-- `Current' reçoit un usager
		do
			print("L'usager embarque dans le véhicule.%N")
		end

	avancer
			-- `Current' commence un déplacement
		deferred
		end

	arreter
			-- `Current' arrête son déplacement
		do
			print("Arrêter le véhicule.%N")
		end

end

Classe CHEVAL:

note
	description: "Un animal de race chevaline dans l'animalerie."
	auteur: "Louis Marchand"
	date: "Mercredi, 25 Août 2021 19:29:24 +0000"
	revision: "0.1"

class
	CHEVAL

inherit
	ANIMAL
	VEHICULE
		redefine
			embarquer,
			arreter
		end

create
	make

feature -- Accès

	cri
			-- <Precursor>
		do
			print("Hiiiiii.%N")
		end

	embarquer
			-- <Precursor>
		do
			print("L'usager embarque sur le cheval.%N")
		end

	arreter
			-- <Precursor>
		do
			print("Le cheval arrête d'avancer.%N")
		end


end

Et voici maintenant un programme qui utilise ces classes:

note
	description: "Exemple d'héritage multiple sans interface avec Eiffel"
	auteur: "Louis Marchand"
	date: "Mercredi, 25 Août 2021 19:29:24 +0000"
	revision: "0.1"

class
	APPLICATION

create
	make

feature {NONE} -- Implémentation

	make
			-- Exécute l'application.
		local
			l_cheval:CHEVAL
			l_automobile:AUTOMOBILE
		do
			create l_cheval.make ("Blacky", 10)
			create l_automobile
			demarrerTransport(l_cheval)
			demarrerTransport(l_automobile)
		end

	demarrerTransport(a_vehicule:VEHICULE)
			-- Démarre `a_vehicule'
		do
			a_vehicule.embarquer
			a_vehicule.avancer
		end

end

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.