TP TUTORIEL GEDsismik
TP TUTORIEL Table of Contents A propos de ce document...1 Langage orienté objet...2 Notion d'objet...2 De l'utilité d'une pile...2 Création du type Pile...2 Interface...3 Implémentation (Manière récursive)...5 Attributs...5 Constructeur...5 Méthodes...6 i
A propos de ce document TP TUTORIEL Par GEDsismik (gedsismik@free.fr) Pris sur le site : http://gedsismik.free.fr Version du : 25/10/2003 A propos de ce document 1
Langage orienté objet Notion d'objet On a l'habitude (enfin, au moins moi) de manipuler des variables somme toutes classique. Ces variables ont un type qui peut être : soit un type primitif (prédéfini par le langage, généralement, on a boolean, integer, real (ou float), double...) soit un type que l'on a défini a partir de types primitifs (comme le complexe formé de deux réels) Le java est orienté objet, c'est a dire qu'il peut utiliser des variables de type un peu particulier. Prenons l'exemple d'un bouton. Un bouton est un type d'objet. On peut agir sur un objet à l'aide de méthodes qui sont définies par la personne qui a créé ce type objet. Dans le cas du bouton, je connais pas vraiment le créateur mais je peux quand même utiliser ce type. Un bouton a un texte, généralement "OK" ou "Annuler". On peut utiliser la méthode label (je parle en cas général, je sais pas si cette méthode s'appelle label en java) pour changer ce texte. Pour cet exemple, on créé donc un objet de type bouton (là, pareil, ca m'étonnerait que ce soit du java pur ce que je fais) : Bouton monbouton=new Bouton(); maintenant, je vais définir le texte qu'il y a dessus : monbouton.label("valider"); Notez qu'un objet est rattaché à la méthode que l'on applique par un point. C'est le label de monbouton que je change. Les paramètres sont placés entre parenthèse comme une procédure ou une fonction. De l'utilité d'une pile Bon, on sait maintenant ce qu'est un objet. C'est cool. On en connait pas jusqu'ici mais c'est pas grave. Imaginons qu'on veuille se lancer dans la programmation direct. On programme par exemple... un jeu de tarot! Bon, un jeu de tarot, c'est constitué de quoi? D'une pile de carte. Bon, bah, on va créé un type objet carte et une type objet Pile (Je passe le type objet carte, on a qu'a dire qu'il est fait, ca a pas grand interet pour comprendre les piles). Création du type Pile Bon! Alors? Comment créé t on un objet en java (parce qu'evidemment, on a choisi java)? Alors, un type Objet Java dit Type Abstrait (TA) se compose de deux fichiers : une interface contenant "le squelette" du TA une implementation contenant "le corps" OK, ben, on y va. Langage orienté objet 2
Interface On créé le type Pile donc on va commencer par créer un fichier texte Pile.java. Vala, créé. Quoi qu'on fait maintenant? Ben, comme tout début de programme, y'a un genre de "phrase d'introduction". public interface Pile C'est l'interface de mon type Pile donc "interface Pile". Le public signifie qu'on pourra avoir accès à cette interface à partir des autres classes (classe? on verra plus tard). Bon, faut définir les méthodes maintenant. Les méthodes, ce sont les "procédures" qui agiront sur un objet qui sera de type Pile. Les méthodes peuvent servir à donner le contenu d'un objet ou à le modifier (comme mon label). Déjà, y'en aura pas qu'une, on ouvre donc un bloc { Un bloc est un ensemble d'instructions. On l'ouvre (selon les langages) avec des accolades. Que peut on mettre comme méthode? Ben, déjà, ca peut etre sympa de savoir si un objet de type Pile (on va dire une pile, plus court) est vide ou pas. Bon, alors elle est vide ou non, c'est binaire, on a besoin que de renvoyer une valeur d'un type ne contenant que deux valeurs possibles (un peu compliquée pour une phrase si simple. Relisez la si besoin est). Boolean semble bien correspondre à la définition. un booléen est soit vrai, soit faux. Une pile est soit vide, soit non vide. Bon, pour l'accès, on garde public, pourquoi changer? Il lui faut un nom à cette méthode. On va mettre estvide. A t on besoin de paramètre? Ben, non, juste de la pile en question donc, pas besoin d'en ajouter. Ca doit donner à peu près ca : public boolean estvide(); Quoi mettre d'autres? Pour l'instant, on fait rien avec une pile, faut ptet qu'on puisse ajouter un élement. De quel type ca peut etre comme méthode ça? On a une pile et on récupère une pile avec un élement en plus.. ben, une pile (Whaa! Comment je suis trop fort). On va garder public tout le temps, plus la peine de préciser. Bon ben voilà. Mmm... Y'a comme un problème là.. Comment savoir quel élement ajouter? On en prend un au hasard? Le mieux, c'est de passer un élement en paramètre. Ca va être de quel type ça un élement? Logiquement, c'est de type Carte puisqu'à l'origine, on voulait un jeu de tarot. Comme j'aimerais pouvoir me servir de mon TA pour autre chose (comme la succession des pièces d'un Tetris par exemple), on va généraliser en mettant Object. Object, c'est un genre de super type qui comprend tout les types objets. Notre pile pourra contenir des cartes comme des pièces de Tetris sans qu'on est à revoir la programmation du TA Pile. OK, c'est bon, on file un nom à l'objet (au hasard o pour objet) et à la méthode (empiler, ca ira très bien). public Pile empiler(object o); Comme on peut empiler un élement, on peut avoir à dépiler. En fait, c'est même très logique parce que sinon, on ne peut plus accéder aux cartes (ou autre élement) qui sont recouvertes. Ce qui serait, évidemment, très génant. Bon, alors... On a une pile et on récupère une pile avec un élement en moins. On renvoie donc une pile. On va appeller cette méthode depiler, ca ira très bien (évitez les accents dans les noms de méthodes ou variables). Est ce qu'il faut des paramètres? Reflexion... A votre avis? Ben, en fait, on pourrait très bien utiliser un paramètre pour récupérer l'élement dépiler. Personnellement, je ne vais pas en mettre. La méthode ne fera que dépiler sans se préoccuper de l'élement qui est oté. D'autres paramètres? J'en vois pas comme ça, donc hop là! Création : public Pile depiler(); Interface 3
D'autres méthodes? Non? Si. On peut enlever ou mettre un élement dans la pile, ok. Maintenant, il faut pouvoir avoir accès aux cartes (ou autres élements) de cette pile. Dans le cas d'une pile, on n'a besoin de connaitre que la première du tas (on distribue pas en prenant les cartes au milieu). Donc, on va faire une méthode pour avoir la valeur de cette fameuse première carte. On a une pile et on veut une carte. On renvoie donc un objet Object (souvenez vous : on veut pouvoir réutiliser le TA pour d'autres programmes qui n'utilisent pas forcement des cartes). Pour le nom, on peut prendre n'importe quoi comme d'hab : premier, sommet, tartopom.. un identificateur un minimum logique serait mieux, sommet ira très bien. Besoin de paramètre? Ben, ma foi non. On récupère juste une carte, ça suffit : public Object sommet(); A t on besoin d'autres méthodes? Ben, là, comme ça, ca devrait aller. On verra plus tard si il faut étendre le TA. Fermons donc le bloc. TP TUTORIEL Ch'est une zoulie n'interface, non? Vi, mais ce n'est qu'une interface : elle ne sert pas à grand chose comme ça. Passons aux choses sérieuses... Interface 4
Implémentation (Manière récursive) Bon! Second fichier : l'implémentation. Mais quoi qu'est ce que cela? Ben, en fait, on a défini le squelette de nos méthodes, maintenant, va falloir réellement les créer. public class PileRec implements Pile { Pourquoi PileRec? Ben, déjà, faut un nom différent de Pile (car Pile.java existe : c'est l'interface du TA Pile). Pourquoi PileRec plutôt que PileJudoranj? Ben, en fait, en programmation, on peut différencier deux "façons" de réfléchir (et donc de programmer) : manière itérative : c'est la manière dite "classique". On utilise ce qu'on connait : conditions, boucles.. manière récursive : en fait, la manière récursive, c'est quand on utilise une méthode (par exemple) dans sa définition. Mais kékidilui?? Explication dans les attributs : Attributs On va définir les attributs. (Hola! récursive, attribut.. il cherche à nous embrouiller lui.) En fait, les attributs d'un type, c'est ce qui compose ce type. Les attributs du type complexe, c'est réel Re et réel Im. Ca va? C'est pas trop compliqué? Bon! Donc, je disais, on va définir les attributs d'une Pile. Et on va le faire de manière récursive (Ca y'est! Il recommence! A croire qu'il veut vraiment que je retourne regarder Popstars). Les attributs définissent un type, on est d'accord? La manière récursive, c'est définir en utilisant ce qui est défini, on est d'accord? Donc, on va définir la Pile en utilisant une Pile. Je ne peux pas expliquer la manière de penser qui amène à la définition qui va suivre (je sais pas si j'aurais eu l'idée) mais je peux vous expliquer pourquoi on la définit ainsi. Si on prend une carte dans une pile, on a une carte et une pile (qui contient une carte de moins que la pile avant qu'on tire la carte). On dit donc qu'une pile est constituée d'un élement (une carte) et d'une pile d'élements (de cartes). On définit les attributs ainsi : On a une carte (un objet Object) que l'on appelle sommet Object sommet; et on a la pile qui reste après avoir tiré cette carte (que l'on va appeller reste) PileRec reste; Il reste du monde? Cool! On continue. Constructeur On va maintenant faire le/les constructeur(s). Mais késako? En fait, un constructeur, c'est un genre de procédure qui contient les instructions à effectuer quand on initialise l'objet. Exemple, si on fait un type tamagoshi, quand on créé un tamagoshi, il faut initialiser son age à 0. Logique, il vient de naitre. Dans notre cas, que mettre alors? Quand on initialise une pile, on a besoin de quoi? Ben, juste de la création des variables sommet et reste. Bon, ok! On laisse le constructeur vide : public PileRec() { On note que le constructeur est un genre de méthode sans type et ayant le nom de la classe. Implémentation (Manière récursive) 5
Méthodes TP TUTORIEL Maintenant, on va créer les méthodes elles même. Commencons par estvide(). Deja, on retape la ligne telle qu'elle est dans l'interface sans le point virgule : public boolean estvide() { on ouvre une accolade pour "accueillir" la suite d'instruction. estvide() est chargé de dire si la pile est vide. Question : dans quel cas peut on dire qu'une pile est vide? Ben, une pile est vide quand il n'y a pas de carte la composant. En gros, quand il n'y a pas de sommet. "Pas de sommet" se définit en java comme "sommet est nul". Premier reflexe : on fait une condition : "Si le sommet est nul, on renvoie vrai sinon, on renvoie faux" On complique pas vraiment ce qu'on vient de dire là. Sauf qu'à programmer, c'est plutôt limpide : if (sommet==null) return true; else return false; Note : sommet sera le sommet de la pile sur laquelle on fait agir estvide(). C'est bien, ca marche. Mais perso, je trouve ça trop long. Je suis plutôt paresseux de nature, je l'avoue. Reflechissons, on sait qu'on doit renvoyer un boolean ; ons ait aussi qu'une condition est un boolean... comment ça "QUOI?"? Ben oui, dans if (condition), condition est un boolean. Le if réalise le bloc d'instruction si la condition est vrai (vaut true) donc, c'est un boolean. (sommet==null) est donc un boolean qui vaut true quand le sommet est nul (la pile est vide) et false quand le sommet n'est pas nul (la pile non vide). (air faussement étonné) Comme que c'est bizarre : c'est exactement ce qu'on veut que revoie estvide(). Ben, on va pas se géner tiens : on renvoie (sommet==null). return (sommet==null); Ca, c'est de la méthode comme je l'aime : une ligne. Bon, on passe à sommet(). On rappelle que sommet() renvoie l'objet (la carte situé au sommet de la pile On commence par le "squelette" qui était dans l'interface public Object sommet() { Maintenant, on réfléchis un peu (ouais, ca devrait suffir). On a une pile constituée d'un sommet et d'un reste et on a une méthode qui retourne le sommet. Je détaille pas le reste de la reflexion (si il y a un reste). return sommet; pour empiler, on se demerdera pas en une ligne, sorry. Va falloir "gratter" un peu plus. On met déjà l'entête public Pile empiler(object o) { empiler empile un élement dans la pile. On a notre tas de cartes et on veut en ajouter une. Que tous ceux qui ont dit "on la pose juste sur le tas" sortent. Bon, on reprend. Une pile est constituée d'une pile (servant de reste) et d'une carte. On a qu'à dire qu'on veut ajouter l'as de coeur pour comprendre le principe. La pioche contient une carte, le deux de carreau et le reste de la pioche. On veut donc une pile ayant pour reste la pioche et pour sommet l'as de coeur. On créé donc une pile tmp contenant la pile actuelle avec le deux de carreau et son reste. La pile que l'on veut contient comme sommet l'as de coeur et comme reste tmp. Ben, c'est bon, on y Méthodes 6
va : On créé une Pile appellé tmp (Pile tmp) et on l'initialise (new PileRec();) Pile tmp=new PileRec(); on la remplie avec la pile que l'on a déjà. : on met le sommet TP TUTORIEL on met le reste tmp.sommet=sommet; tmp.reste=reste; on met l'as de coeur dans le sommet actuel : sommet=o; l'as de coeur est passé en paramètre, c'est donc o. On place la pile tmp comme reste de la pile actuelle. reste=tmp; il nous reste plus qu'a retourner la pile actuelle : return this; Passons à depiler. Entete : public Pile depiler() { Pour depiler, on a un problème potentiel : on ne peut enlever un élement d'une pile vide. On va écarter le problème avec une condition : Si la pile est vide if (estvide()) { // balance un message d'erreur (System.out.println pour les erreurs) System.err.println("Pile : préconditions non vérifiées"); // et sort du programme System.exit(1); Bon, on est sur que la pile est non vide si on est encore dans le programme. On continue donc. depiler dépile un élement du sommet. On a une pile contenant une carte et une pile comme reste. On veut la pile sans cette carte. En gros, on veut le reste. Le reste, c'est quoi? Une pile. Le reste possède donc un sommet et un reste. On met donc la pile actuelle égale au reste en mettant leur sommet et leur reste égaux : sommet=reste.sommet; reste=reste.reste; on retourne simplement la pile actuelle. return this; Méthodes 7