Les interfaces en Java

Voici un petit cours/tutos sur les interfaces en java. Le but n’est pas d’expliquer en profondeur le fonctionnement des interfaces, cela ayant déjà été fait par pas mal de gens.Pour la théorie je recommande deux ouvrages, le premier, chez Eyrolles, “Programmer en Java” de Claude Delannoy, Ingénieur au CNRS, dans la collection BestOf. Une véritable bible du développeur Java à petit prix (800 pages, 19 € prix couverture) déjà vendu à 250 000 exemplaires, traduit en plusieurs langues (ce qui est remarquable pour un livre technique de ce type). Ce serait un crime de ne pas se jeter dessus. Un second, plus générique, toujours chez Eyrolles, “La programmation Orientée Objet, Cours et Exercices en UML2, Java, C#, C++, Python, PHP et Linq” par Hughes Bersini, Ingénieur physicien et Directeur du Laboratoire sur l’intelligence artificielle à l’ULB (Université Libre de Bruxelles), un pédagogue exceptionnel et ouvert que j’ai d’ailleurs eu l’occasion de rencontrer il y a quelques mois dans le cadre d’un salon sur le logiciel libre. 600 pages +/- à 35 € prix couverture. Bon, ceci étant dit, je pars du principe que la théorie de l’héritage, le polymorphisme, l’abstraction et les règles de bases qui sous-tendent l’OO sont connues (pas forcément maîtrisées). Passons au but de l’article, montrer en quoi les interfaces sont réellement un outil/concept utile à la conception d’un logiciel et offre une réelle abstraction supplémentaire par rapport aux classes abstraites et à l’héritage de classes abstraites. En effet, à la lecture de beaucoup de cours, les interfaces sont souvent très bien expliquées dans la théorie mais pas dans la pratique, ce qui, au final, donne la sensation au lecteur qu’une interface est juste une classe abstraite sans l’implémentation des méthodes de classes.
Pourquoi ? Voici un exemple standard vraiment simple qui ressort dans presque tous les cours/tutos :

Humain.java :

Garçon.java :

Main.java :

Cet exemple est tiré directement d’un cours, considéré comme une référence, paru chez O’reilly (comme la plupart de leurs livres). Ceci ne montre rien des interfaces à part le fait que l’on implémente une interface Humain dans Garçon et que l’on redéfinit la méthode d’interface respirer() dans Garçon. Ensuite on crée un objet Garçon(), nommé Jean puis, on fait respirer Jean. Dans cet exemple, la plupart des lecteurs se disent : “Un Garçon est un humain et il respire… Ok… Mais moi dans mon code, vu que tous les humains respirent, garçons ou filles, et de la même manière, je ne vais pas redéfinir la méthode respirer chaque fois, ça ne me sert a rien ! Hum… Je vais plutôt faire une classe abstraite Humain et Garçon héritera de Humain !” Et cette réaction est légitime, car en effet cet exemple (et la plupart de ceux que l’on trouve) est dénué de sens pour quelqu’un qui aborde le sujet et sort en général du chapitre sur les abstractions. (Dans tous les livres que j’ai, quel que soit le langage, si on parle d’abstraction, le chapitre suivant sera 9 fois sur 10 les interfaces…).

J’ai donc fait un exemple pour rendre justice aux interfaces et que vous compreniez en quoi la redéfinition de méthode est vraiment utile. Voici la situation à modéliser.

“Je veux un tableau d’objet, ces objets seront des êtres vivants, je veux pouvoir les faire mourir et ressusciter selon le type d’êtres vivants.”

Un besoin très simple, J’ai donc une interface Vivant, cette interface a 3 méthodes, la première retourne une valeur booléenne sur l’état de l’être (true ou false), la seconde le tue, la troisième le ressuscite. L’interface est donc un dénominateur commun de méthodes à tous les êtres vivants. Maintenant il faut implémenter cette interface. Nous allons créer basiquement deux classes, Humain et Chat. Sur ces deux types d’êtres vivants on peut implémenter sans aucun souci les comportements demandés dans le besoin et définis dans l’interface. La où la redéfinition, grâce aux interfaces, sera utile, c’est au niveau de la résurrection. En effet, un humain ne peut ressusciter (ou alors il faudrait créer une classe supplémentaire Saint), par contre un chat a plusieurs vies, on peut donc dire qu’il peut “ressusciter”.

Voici le code que l’on obtient avec l’utilisation correcte des interfaces pour ce besoin :

Vivant.java :

Humain.java

Chat.java :

Main.java

Alors, pour le code de l’interface, rien de bien mystérieux. Sur humain on a donc implémenté Vivant, on a défini un attribut boolean livin sur son état, la méthode is_alive() retourne simplement livin, la méthode kill() vérifie que l’humain n’est pas déjà mort, si ce n’est pas le cas (que livin est a true), on le tue, sinon on prévient qu’il est déjà mort et la méthode ressusciter renvoie simplement que JP n’est pas JC. Pour la classe chat, on a le même attribut livin que sur humain, on a juste un attribut intégré en plus contenant le nombre de vies restant au chat, la méthode is_alive a le même comportement que Humain, kill également, par contre ressusciter a un comportement différent. Sur le premier if, on vérifie que le chat a encore des vies et qu’il est mort, si c’est le cas, on le ressuscite en passant livin a true et on lui enlève une vie, si on veut le ressusciter mais qu’il n’est pas mort ou alors qu’il ne lui reste plus de vie on prévient l’utilisateur selon la situation. Enfin, dans main.java, c’est à ce niveau que tout va se jouer. Dans la plupart des cours on aurait créé un objet Chat et un objet Humain, mais les interfaces jouent un rôle d’abstraction, ce qui veut dire que l’on peut créer (comme demandé dans le besoin) un tableau d’objets du type de l’interface. On peut donc créer un tableau de vivants. On initialisera ensuite chaque objet selon le type de vivant, par exemple un chat ou un humain. Et là où l’abstraction est vraiment utile c’est que, vu que ces classes implémentent les mêmes méthodes, celles définies dans l’interface, on peut dans une boucle for par exemple, appeler ses méthodes sans connaître le type ‘final’ de l’objet sur lequel on travaille. On peut donc tuer tous les êtres vivants du tableau sans savoir si on a affaire à un humain, un chat, un chien, un cochon, de plus ce n’est pas le but, on veut tuer les êtres vivants du tableau, on se moque de savoir de quel être vivant il s’agit. Voici le dernier point qui est souvent mal détaillé dans les cours, l’abstraction que les interfaces proposent, ce qui, en plus de forcer la redéfinition, est la différence fondamentale entre classes abstraites et interfaces. Dans main.java on créé donc un array de size[2], un tableau de vivants que l’on nomme etres_vivant, on crée à l’index 0 un chat et à l’index 1 un Humain. Ensuite on a un for(x;x;x) qui parcourt le tableau et qui sur chaque objet, fait des appels de méthodes :

1. Savoir s’il est vivant

2. Le faire mourir

3. Le ressusciter

4. Le ressusciter

5. Le tuer

6. Le ressusciter

7. Savoir s’il est vivant

Ce qui nous donne dans la sortie standard :

C’est tout pour les interfaces, j’espère avoir pu expliquer clairement une des vraies utilités des interfaces. Les exemples ici sont en Java, mais le fonctionnement et la sémantique restent les mêmes dans la plupart des langages OO permettant l’utilisation d’interface (C# par exemple).

Sur ce…

6 thoughts on “Les interfaces en Java

  1. Sliim

    Yo Manu,

    sympa l’exemple, très bien expliqué GG à toi :p. Il est vrai que l’utilité des interfaces n’est pas simple à comprendre et qu’on se dirige plutôt vers des classes abstraites..

    Une autre utilité fondamentale est, par exemple pour une API, d’obliger les développeurs qui voudront implémenter notre interface dans leur classe à déclarer certaines méthodes spécifiques pour l’application. Chose impossible avec des classes abstraites (en tout cas pas à ma connaissance ^^).

    ++

    Reply
  2. manu404 Post author

    Sliim :

    Une autre utilité fondamentale est, par exemple pour une API, d’obliger les développeurs qui voudront implémenter notre interface dans leur classe à déclarer certaines méthodes spécifiques pour l’application. Chose impossible avec des classes abstraites (en tout cas pas à ma connaissance ^^).

    ++

    Ca fera l’objet d’un second article, l’utilisé des interface dans les API que l’on développe ou la je mélangerai justement les interfaces et les classes abstraites pour la création d’un JPanel personnalisé, qui par exemple, héritera donc de la classe abstraites JPanel et implémentera MouseListenner.

    Reply
  3. foua

    salut,j’ai lu l’exemple proposé mais j’ai toujours une nuance entre une classe abstraite et une interface .
    selon l’exemple est ce qu’on aurait pu faire une classe abstraite Vivant et considéré les classes Humain et Chat comme des classes héritées de la classe Vivant sans utilisé les interfaces .
    je tient à vous faire savoir que je viens de débuté la programmation java.
    merci d’avance.

    Reply
    1. manu404 Post author

      Oui sans problème mais alors tu ne force pas la redéfinition des méthodes. Tu peux override les méthodes mais rien ne t’y oblige. L’intérêt des interface ici, c’est que un humain et un chats peuvent tous deux mourir et “ressusciter”, cependant, un humain qui ressuscite tiendrais de “l’action divine” alors que un chat ne fait que décompter une de ses 7 vies. C’est ici que l’on voit l’intérêt de forcer la redéfinition des méthodes. Si tu voulais une classe humain qui puisse ressusciter, il te suffirais alors de créé une seconde classe, par exemple “demi_dieux”, qui lui adopterais un comportement similaire a la classe Chat.

      Reply
  4. Bilou

    Salut,

    Beau boulot, ton tuto est vraiment intéressant, et je sais qu’il date un peu mais j’ai une question qui me taraude, car je n’arrive toujours pas à comprendre l’intérêt d’une interface.

    Dans ta réponse à Foua, je te cite tu dis :
    ” tu ne force pas la redéfinition des méthodes. Tu peux override les méthodes mais rien ne t’y oblige.”

    Je pense que la nuance entre une classe abstraite et une interface est là, mais je ne saisis pas le concept.

    Quel serait le réel problème que d’avoir toutes les méthodes dans une fameuse classe abstraite Vivant, et de les définir ensuite dans les classes Chat et Humain ?

    Ce que je veux dire, c’est que dans tous les cas les méthodes vont devoir être overridées, que ce soit avec une interface ou une classe abstraite ?

    Bon tant que j’y suis j’ai une question à te poser, et si on avait créé une classe mère Vivant (comprenant une méthode affichant “Coucou”), avec deux classes filles Chat et Humain, et une interface Comportement avec à l’intérieur toutes les méthodes que tu as décrit.

    Quand tu crées un objet Chat avec l’interface Comportement tu ne peux pas accéder à la méthode mère Coucou ?

    Comportement chat = new Chat();

    Merci

    Reply
    1. Emmanuel Istace Post author

      Salut Bilou,

      Désolé d’avance ca fait un bail que je ne fait plus de java, je suis passé à C# il y a 4/5ans…

      En fait tu peux. Tu peux avoir une interface ISomething avec une classe SomethingBase qui sera abstract et fournirais une implémentation par defaut tout en gardant le typage fort et la flexibilité de l’interface pour les classes d’implémentations.

      Pour la suite je ne vois pas ou serais le problème. Un exemple :

      public interface IVivant
      {
      void IAction();
      void IAction2();
      }

      public abstract class VivantBase implements IVivant
      {
      public void IAction()
      {
      System.out.println(“IAction – Implementation VivantBase”);
      }

      public void ActionAbstract()
      {
      System.out.println(“ActionAbstract – Implementation VivantBase”);
      }
      }

      public class ImplementationVivantBase extends VivantBase
      {
      // Obligé de fournir une implémenation pour IAction2() et peu
      // overrider l’implémentation de IAction()
      }

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s