Outils pour utilisateurs

Outils du site


java:abstract

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
java:abstract [2013/11/07 14:11] – [Allons un peu plus loin: les méthodes virtuelles (ou abstraites)] brunojava:abstract [2018/03/16 15:42] (Version actuelle) – [Pour aller encore plus loin: les classes virtuelles pures (ou interfaces en java)] bruno
Ligne 1: Ligne 1:
 ====== Abstract et java ====== ====== Abstract et java ======
 +
 +> "Le concret c'est de l'abstrait rendu familier par l'usage." (Paul Longevin)
 +
 Nous voyons aujourd'hui dans ce TP guidé un concept qui porte malheureusement bien souvent son nom: **abstract**. Nous voyons aujourd'hui dans ce TP guidé un concept qui porte malheureusement bien souvent son nom: **abstract**.
  
-En effet, très souvent, les débutants en java et plus généralement en objet ne comprennent pas à quoi il sert, et donc l'utilise à tord et à travers.+En effet, très souvent, les débutants en java et plus généralement en objet ne comprennent pas à quoi il sert, et donc l'utilisent à tord et à travers.
  
 Heureusement, dans 30 minutes maximum, vous constaterez que c'est en réalité **très** simple! Heureusement, dans 30 minutes maximum, vous constaterez que c'est en réalité **très** simple!
Ligne 8: Ligne 11:
 C'est parti! C'est parti!
  
-===== Un peu de théorie histoire de bien situer le contexte =====+===== Un peu de théorie histoire de bien situer la problématique =====
  
-Je vais commencer par un peu de théorie de la programmation orientée objet.+> Plus abstraite est la vérité que tu veux enseigner, plus tu dois en sa faveur séduire les sens. (Friedrich Nietzsche) 
 +  
 +Je vais commencer par essayer de vous séduire avec un peu de théorie de la programmation orientée objet (certain diront que c'est pas gagné d'avance, mais j'aimerais bien voir Nietzsche à ma place ;-)).
  
 Vous savez normalement ce qu'est l'héritage. Ce concept est directement lié à l'utilisation de //abstract//. Vous savez normalement ce qu'est l'héritage. Ce concept est directement lié à l'utilisation de //abstract//.
 +
 +Or, bien souvent, il est délicat d'imaginer dès le départ tous les comportements possibles dans une hiérarchie. De plus, les classes mères de haut niveaux ne sont pas toujours utiles en tant qu'instance, et servent juste à regrouper leurs héritiers.
 +
 +Ces classes mères permettent avant tout de donner une direction générale à la programmation, au //modèle//, mais ne peuvent pas toujours tout prévoir.
 +
 +Nous savons qu'il est possible de //redéfinir// des comportements (par exemple, //toString()//, //equals()//, etc.).
 +
 +Mais pour l'instant, nous ne savons pas encore comment contraindre les héritiers à préciser leur comportement en redéfinissant des méthodes.
 +
 +Nous allons voir ici que justement, la programmation objet permet de résoudre ces problèmes.
 +
 +Nous allons découvrir trois manières de traiter l'abstraction en programmation orientée objet, et plus précisément avec java:
 +  - les classes abstraites;
 +  - les méthodes virtuelles (ou abstraites);
 +  - les classes virtuelles pures (ou interface en java).
 +
 +===== Passons à la pratique! =====
 +
  
 Prenons un premier exemple simple: mon sujet d'étude est la représentation d'Animaux dans un Zoo (ou un centre SPA si vous préférez). L'objectif est de décrire tous les types d'Animaux du zoo, de les faire jouer entre eux et de les faire manger. Prenons un premier exemple simple: mon sujet d'étude est la représentation d'Animaux dans un Zoo (ou un centre SPA si vous préférez). L'objectif est de décrire tous les types d'Animaux du zoo, de les faire jouer entre eux et de les faire manger.
Ligne 144: Ligne 167:
 </code> </code>
  
-==== Les classes abstraites ====+===== Les classes abstraites =====
 Dans la hiérarchie que je viens de donner, il n'est pas très utile d'utiliser le constructeur //Animal//: en effet, la classe Animal sert uniquement à regrouper ce qu'il y a de commun entre des héritiers (Chat, Chien, Souris, etc.). Dans la hiérarchie que je viens de donner, il n'est pas très utile d'utiliser le constructeur //Animal//: en effet, la classe Animal sert uniquement à regrouper ce qu'il y a de commun entre des héritiers (Chat, Chien, Souris, etc.).
  
Ligne 206: Ligne 229:
 On voit bien que c'est l'utilisation du constructeur //Animal// avec **new** qui rend impossible la création directe d'instances d'//Animal//. On voit bien que c'est l'utilisation du constructeur //Animal// avec **new** qui rend impossible la création directe d'instances d'//Animal//.
  
-==== Allons un peu plus loin: les méthodes virtuelles (ou abstraites) ====+===== Allons un peu plus loin: les méthodes virtuelles (ou abstraites) =====
  
 Nous avons vu que nous pouvions interdire la création directe d'instances d'une classe lorsque celle-ci n'est pas "intéressante" en tant qu'objet, mais utile pour des raisons de regroupement hiérarchique. Nous avons vu que nous pouvions interdire la création directe d'instances d'une classe lorsque celle-ci n'est pas "intéressante" en tant qu'objet, mais utile pour des raisons de regroupement hiérarchique.
Ligne 217: Ligne 240:
  
 **Hé bien c'est possible!** Nous allons déclarer //jouer// comme étant une méthode //virtuelle// dans la classe Animal. **Hé bien c'est possible!** Nous allons déclarer //jouer// comme étant une méthode //virtuelle// dans la classe Animal.
 +
 +==== Les méthodes virtuelles ou méthodes abstraites ====
  
 Une méthode //virtuelle//: Une méthode //virtuelle//:
Ligne 339: Ligne 364:
 } }
 </code> </code>
 +
 +Notez au passage l'utilisation de getClass() qui renvoie une instance de la classe //Class//.
 +
 +La méthode //toString()// de la classe //Class// renvoie une chaîne du type "class NomDeLaClasse".
 +
 +La méthode //getName()// de la classe //Class// renvoie le nom de la classe uniquement.
 +
 +Pour plus d'info: [[http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html|la class Class dans l'API java]]
  
 <code java Souris.java> <code java Souris.java>
Ligne 420: Ligne 453:
 } }
 </code> </code>
 +
 +L'exécution de la méthode //main// de //TestAbstract// produira l'affichage suivant:
 +
 +<code bash>
 +Je joue avec tout le monde moi!
 +Je joue avec tout le monde moi!
 +Je joue avec tout le monde moi!
 +Je ne joue pas avec les chiens, moi!
 +Je veux bien jouer avec les instances de Chat
 +Je veux bien jouer avec les instances de Souris
 +Je ne joue pas avec les instances de Chien
 +Je ne joue pas avec les instances de Chat
 +Je joue qu'avec mes copines souris, alors oui!
 +Résultat pour dog1:true; true; true
 +Résultat pour cat1:false; true; true
 +Résultat pour mouse1:false; false; true
 +
 +</code>
 +
 +==== Et si je ne veux pas redéfinir une méthode abstraite, hein? ====
 +
 +Vous vous posez peut-être cette question.
 +
 +Hé bien, c'est possible! Mais pas à n'importe quel prix!
 +
 +Les chats sont paresseux, supposons que la classe Chats ne redéfinisse pas la méthode jouer.
 +
 +Que va dire le compilateur? Essayons pour voir! Commentez la méthode jouer dans Chat
 +
 +<code java>
 + /**
 + Pour faire jouer le chat.
 + Affiche un petit message en console.
 + @param a l'animal qui veut jouer avec this
 + @return true si l'animal veut bien jouer avec a
 + */
 + /* Je veux pas redéfinir moi!
 + public boolean jouer(Animal a){
 + boolean ret = true;
 + String message = "Je veux bien jouer avec les instances de " + a.getClass().getName() ;
 + if(a instanceof Chien){
 + ret=false;
 + message = "Je ne joue pas avec les chiens, moi!";
 + }
 + System.out.println(message);
 + return ret;
 + }
 + */
 +</code>
 +
 +Recompilons:
 +
 +<code bash>
 +./Chat.java:22: error: Chat is not abstract and does not override abstract method jouer(Animal) in Animal
 +public class Chat extends Animal{
 +</code>
 +
 +Apparemment, le compilateur semble contrarié. Regardons en détail ce qu'il nous raconte:
 +
 +> "Chat n'est pas abstract" -> ok
 +
 +> "...et ne redéfinit pas la méthode abstraite jouer(Animal)" -> on vient de la commenter...
 +
 +Quel problème cela pose-t-il pour le compilateur: raisonnons par l'absurde.
 +
 +Si le compilateur permettait à Chat de ne **pas** redéfinir la méthode jouer, et également de construire des instances de Chat, que se passerait-il lorsque l'on voudrait appeler la méthode //jouer(Animal)// sur une instance de Chat?
 +
 +Il n'y aurait pas de code défini -> le programme ne saurait pas quoi faire.
 +
 +Le "contrat" donné par //Animal// est que toute instance d'Animal doit pourvoir //jouer// et //manger//.
 +
 +Donc, si ce comportement n'est pas définit dans un héritier d'Animal (Chat), alors il n'est pas possible de créer des instances de //Chat//.
 +
 +Le compilateur propose donc deux solutions:
 +  - soit passer la classe Chat en classe abstraite, afin d'empêcher l'utilisation du constructeur Chat directement;
 +  - soit redéfinir la méthode //jouer// dans Chat, pour permettre la construction d'instances de Chat.
 +
 +Si on choisit la première solution, Chat devient abstract et il n'y a plus de problème de compilation... à condition de ne pas utiliser le constructeur //Chat// avec **new**.
 +
 +Si une classe hérite de Chat (par exemple //ChatJoueur//) et que le programmeur veut créer des instances de //ChatJoueur//, il devra alors redéfinir la méthode //jouer// héritée de Animal par l'intermédiaire de //Chat// dans la classe //ChatJoueur//: on appelle ça "refiler la patate chaude".
 +
 +===== Pour aller encore plus loin: les classes virtuelles pures (ou interfaces en java) =====
 +
 +-> ce dernier point fait l'objet d'un autre TP guidé...
 +
  
java/abstract.1383833481.txt.gz · Dernière modification : 2013/11/07 14:11 de bruno