Polymorphisme et intérêt des interfaces

Polymorphisme et intérêt des interfaces - Java - Programmation

Marsh Posté le 11-12-2016 à 14:02:11    

Bonjour à tous !  :hello:  
 
J'essaie en ce moment de saisir les concepts de la POO avec Java, mais j'ai quelques problèmes (je ne suis pas le premier) avec les interfaces.
J'ai écumé openclassrooms et d'autres sites qui expliquent tous l'intérêt de l'interface, mais je garde une certaine difficulté à les comprendre. Tout n'est pas clair.
De ce que j'ai saisi, une interface permet, en quelque sorte, de faire hériter des méthodes abstraites aux classes qui l'implémentent. Mais je ne vois pas alors la différence que cela peut avoir avec une simple classe mère. J'ai aussi quelques problèmes à comprendre comment utiliser au mieux le polymorphisme.
Admettons par exemple que je code un simple pacman. Voici le diagramme de classes (simplifié) que j'ai pu concevoir (j'ai omis les constructeurs par souci de clarté).

  • Chaque acteur du jeu a une position et une direction, ainsi qu'une méthode move() pour se déplacer dans la direction choisie.
  • La direction de Pacman est contrôlée par l'utilisateur, et il possède une méthode eatPellets() pour manger les petites boules.
  • Les fantômes choisissent leur direction seuls, grâce à la méthode chooseTarget(), qui choisit une cible à atteindre sur le terrain en fonction de leurs intelligence artificielles propres.

https://s28.postimg.org/y7x4bestp/Diagrammedeclasses.png
 
Si j'ai bien compris, dans le code, chaque fantôme pourra être instancié dans un objet Ghost comme suit :

Code :
  1. Ghost blinky = new Blinky();
  2. Ghost pinky = new Pinky();
  3. Ghost inky = new Inky();
  4. Ghost clyde = new Clyde();


Ce qui me permettrait alors de les manipuler dans un tableau afin, par exemple, de les faire bouger tous d'un coup :

Code :
  1. Ghost[] ghosts = {blinky, pinky, inky, clyde};
  2. for (int i = 0; i < ghosts.length(); i++) {
  3.     ghosts[i].move();
  4. }


En revanche, si je comprends bien le polymorphisme, je ne peux instancier pacman que comme ceci :

Code :
  1. Pacman pacman = new Pacman();
  2. // La déclaration suivante échouerait car la classe Pacman possède une méthode qu'Agent ne possède pas
  3. Agent pacman2 = new Pacman();


Ai-je bien compris comment fonctionnait le polymorphisme ?
Dans ce cas-ci, transformer la classe Ghost en interface, faire hériter mes 4 fantômes de Agent directement et leur faire implémenter l'interface Ghost est-il faisable ? Cela aurait-il du sens ? Si oui, quels sont les avantages que cela apporterait ?

Reply

Marsh Posté le 11-12-2016 à 14:02:11   

Reply

Marsh Posté le 12-12-2016 à 01:06:21    

Tu peux hériter de classes concrètes, pas de soucis, mais ici du coup tu pourrais aussi instancier des objets de type Agent ou Ghost, ce que tu ne veux pas normalement.
Ton exemple aurait plus de sens avec des classes abstraites pour ces deux classes, dans le but de partager l'implémentation de certaines méthodes tout en interdisant leur instanciation directe.
Quant aux interfaces, depuis Java 8 elles peuvent fournir une implémentation par défaut des méthodes, mais une classe abstraite peut en plus définir un constructeur et surtout ici, te permettrait d'avoir des membres positionX, positionY, ... non finaux.

 

Tu peux parfaitement instancier une classe non-abstraite et l'assigner à une variable d'un type parent (abstrait ou non):

Code :
  1. Agent pacman2 = new Pacman();
  2. pacman2.move(); // ok, défini pour Agent
  3. pacman2.eatPellets(); // pas possible
  4. ((Pacman) pacman2).eatPellets(); // ok
 

Si tu veux un bon exemple, dans ton IDE ou dans la Javadoc jette un œil à java.util.List, AbstractList et ArrayList.


Message édité par DDT le 12-12-2016 à 01:08:23

---------------
click clack clunka thunk
Reply

Marsh Posté le 12-12-2016 à 15:40:09    

 

Non, cette déclaration est valide.

 

Une interface est un ensemble de comportements que doit avoir une classe, et c'est pourquoi une classe peut avoir plusieurs interfaces. On peut attendre d'elle plusieurs comportements. Pour pacman ce pourrait être d'être un agent (interface Agent) ET d'etre controlable par l'utilisateur (nouvelle interface UserMoveable par ex.)
Mais une interface peut avoir aussi 0 méthodes (google interfaces marqueurs). Une interface est un tag qui montre qu'on peut attendre d'une classe quelle se comporte d'une certaine manière, ou dit autrement, qu'elle implémente certaines méthodes.

 

Une classe abstraite sert à factoriser du code présent dans plusieurs classes similaires. En java on ne peut hériter que d'une classe. Une classe abstraite ne sert donc pas à définir un contrat d'interface mais plus à grouper du code entre plusieurs classes proches ou identiques, comme tes Ghosts.

 

Note que l'un n'empêche pas l'autre. Il serait logique que Ghost hérite de AbstractGhost pour factoriser le code commun, et que AbstractGhost implémente l'interface IGhost, qui définit les méthodes que le reste du programme peut s'attendre de voir un Ghost implémenter: le contrat d'interface.


Message édité par gelatine_velue le 12-12-2016 à 15:40:22
Reply

Marsh Posté le 12-12-2016 à 16:02:11    

Si tu préfixes le nom de tes interfaces avec I en Java je te mets un coup de pelle lors des revues de code. :o


---------------
click clack clunka thunk
Reply

Marsh Posté le 12-12-2016 à 19:50:55    

DDT a écrit :

Si tu préfixes le nom de tes interfaces avec I en Java je te mets un coup de pelle lors des revues de code. :o

 

C'est pour etre le moins ambigu possible dans mon explication, j'etais SUR que qqun allait faire la remarque. :D
Donc petit aparte pour les novices: ne le faites pas selon avec qui vous codez, pas plus que mettre Abstract devant vos classes abstraites, ca peut ne pas passer.
Perso je m'en fous je m'adapte, je considere que c'est pas important.

Message cité 1 fois
Message édité par gelatine_velue le 12-12-2016 à 19:55:31
Reply

Marsh Posté le 12-12-2016 à 23:03:43    

gelatine_velue a écrit :


 
C'est pour etre le moins ambigu possible dans mon explication, j'etais SUR que qqun allait faire la remarque. :D
Donc petit aparte pour les novices: ne le faites pas selon avec qui vous codez, pas plus que mettre Abstract devant vos classes abstraites, ca peut ne pas passer.  
Perso je m'en fous je m'adapte, je considere que c'est pas important.


 
Pourtant checkstyle et PMD grognent quant il n'y a pas de Abstract devant les classes abstraites, je conseillerais plutôt de le mettre ainsi que Impl comme suffixe des implémentations d'interface...  ;)

Reply

Marsh Posté le 13-12-2016 à 06:20:02    

hmmm sur mon ancien projet, on doit trouver plusieurs centaines (milliers?) d'interfaces qui commencent par I.
On sait immédiatement si l'algo qui consomme les objets est générique ou spécialisé.
 
Ce serait quoi les bonnes raisons de ne pas mettre I?

Message cité 1 fois
Message édité par antiseptiqueincolore le 13-12-2016 à 06:20:17
Reply

Marsh Posté le 13-12-2016 à 11:21:51    

Le C# c'est à côté. :spamafote:
 
Tous les projets sérieux en Java suivent les conventions de nommage du langage.
Regarde les dizaines/centaines de dépendances open source dans ton classpath... si ces projets y arrivent, pourquoi pas toi?
 
http://stackoverflow.com/a/2814831/2934360


---------------
click clack clunka thunk
Reply

Marsh Posté le 13-12-2016 à 20:00:24    

sujet très sensible  :D  un peu comme les réglages de sonarqube sur ce qui est acceptable ou pas.
et en général j'aime bien contester  :D je ne vais pas le faire  [:ddr555]

Reply

Marsh Posté le 17-12-2016 à 14:15:26    

antiseptiqueincolore a écrit :


 
Ce serait quoi les bonnes raisons de ne pas mettre I?


Parce que c'est dérivé de la notation hongroise qui est devenue totalement inutile avec les langages typés, elle pollue le code et les yeux avec une information que l'utilisateur de ton interface n'a pas besoin de connaitre.


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 17-12-2016 à 14:15:26   

Reply

Marsh Posté le 18-12-2016 à 21:57:59    

http://reho.st/https://www.jmdoudoux.fr/java/dej/images/collections_001.png
J'ai beaucoup de mal à savoir ce que je peux instancier là dedans....Sauf par habitude. (ils ont bien ajouté class ou interface pour qu'on sache  :whistle: )
 
Je suis d'accord qu'une interface est un type mais rajouter I devant, me dit immédiatement que ce type n'est pas instanciable (tout comme A).
C'est une information supplémentaire. A plus forte raison si ça a été fait par un autre développeur et que je dois me brancher sur son code (et qu'en plus je n'ai que 4 heures)
Je suis ouvert mais c'est une information dont je me sers réellement!
 
 

Reply

Marsh Posté le 19-12-2016 à 11:23:58    

Si tu regardes bien, la seule différence entre une interface et une classe abstraite est le fait qu'une interface ne peut pas avoir de membres private. Tous ses membres sont publics. C'est une différence très minime, il n'y a donc aucune raison de distinguer un type abstrait d'un type interface, ça ne fait que rajouter de la confusion visuelle.
C'est d'autant plus vrai en Java que ce langage possède des mots clés explicites pour différencier si on implémente une interface ou si on hérite d'une classe : implements et extends, rendant cette distinction encore moins pertinente.
A la rigueur, en C#, le "I" pourrait s'expliquer car l'implémentation ou l'héritage ne sont pas distingués (on utilise ":" dans les deux cas).
Tous les IDE permettent de distinguer une interface en plaçant une icône devant leur définition (géneralement un "I" entouré).
De plus, il se pose un problème ergonomique : si tu recherches un nom de classe dans ton IDE, la partie la plus significative de ta recherche est le début de ta chaine. En préfixant tes interfaces (par "I" par exemple), tu vas avoir tout un paquet de chaines qui commencent par "I", mais qui sont néanmoins similaires, ce qui rendra leur distinction plus difficile.


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed