1 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde COURS 3 : Programmation impérative Résumé du cours précédent
2 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde classe MainDominos +$ main(String[]) { test1(); } +$ test1() { Domino d4 = new Domino(3,4); if ( ) { // faire quelque chose... } classe Domino m1 : int m2 : int +Domino(int,int) +Domino(int) +Domino() public boolean estDouble(){ } return ( == ); this.m1 this.m2 invocation de la méthode mise à jour de « this » exécution de la méthode Maintenant « this » réfère à d4 Et ce nest quensuite que Java exécute la méthode dans sa classe propre. d4.estDouble()
3 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Classes&objets: CONSTRUCTEURS, VARIABLES et METHODES DINSTANCE classe Domino m1 : int m2 : int +Domino(int,int) +Domino(int) +Domino() Classes & Objets = VARIABLES DINSTANCES (=ATTRIBUTS) + CONSTRUCTEURS + METHODES DINSTANCES +dominoToString(): String +estDouble(): boolean +valeur() : int +plusGrandQue(Domino d) : int +plusGrandeMarque() : int CONSTRUCTEURS METHODES DINSTANCE Cest de cette manière que les objets et leurs classes doivent être conçus dans le paradigme Orienté-Objet. VARIABLES DINSTANCE ATTRIBUTS ou ETAT En Orienté-Objet, un objet est vu comme une entité qui encapsule un état interne (ensemble des valeurs des var. dinst.) et qui fournit des services (méth. dinst.) par rapport à cet état.
4 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Classes&objets: CONSTRUCTEURS, VARIABLES et METHODES DINSTANCE classe Domino m1 : int m2 : int +Domino(int,int) +Domino(int) +Domino() classe Book (anglicisée) title : String autor : String editor : String nbPages : int isbn : ISBN +Book(String,String,String, int,ISBN) classe ISBN (anglicisée) groupA : int groupB : int groupC : String groupD : String +ISBN(int,int,String,String) +dominoToString(): String +estDouble(): boolean +valeur(): int +plusGrandQue(Domino d): int +plusGrandeMarque(): int +bookToString(): String +hasAutor(String firstname, String lastname): boolean +isFrancophone(): boolean +isEditedBy (String): boolean +isEditedBy(int): boolean +isbnToString(): String +isFrancophone(): boolean +isEditedBy (int): boolean classe MainDominos et classe MainBooks +$main(String[]): void +$test1(): void +$test2(): void FIRST NAME : prénom / LAST NAME : nom de famille / MIDDLE NAMES : autres prénoms
5 Objectifs de ce cours (I21) Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Maintenant !
6 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Classes&objets : VÉRITABLES ENTITÉS AUTONOMES*
7 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Classes&objets : le problème des ENSEMBLES dOBJETS Mais les problèmes réels manipulent – le plus souvent – de nombreuses données dun même type :
8 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde COMMENT AVONS-NOUS TRAITÉ LES ENSEMBLES DOBJETS JUSQUE LÀ ? Le simple fait dutiliser des tableaux dobjets nest pas satisfaisant en Orienté-Objet car on ne peut leurs associer aucune méthode dinstance. Tout juste possèdent-t-ils une variable dinstance length (constante). classe MainDominos +$ main(String[]) { test1(); } +$ test1() { Domino[] miniJeu = { new Domino(0,0), new Domino(0,1), new Domino(0,2) }; System.out.println( "Jeu contenant " + miniJeu.length + " dominos"); System.out.println( setDominosToString (miniJeu)); } +$ setDominosToString(Domino[] setDominos) { String s = ""; for( Domino d : setDominos ) { s += d. dominoToString (); } return s; } AGIT SUR LE TABLEAU DE DOMINOS => méthode dinstance IMPOSSIBLE ici AGIT SUR LE TABLEAU DE DOMINOS => méthode dinstance IMPOSSIBLE ici NAGIT QUE SUR UN SEUL DOMINO => méthode dinstance de la classe Domino NAGIT QUE SUR UN SEUL DOMINO => méthode dinstance de la classe Domino Exemple :
9 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Solution : classe JeuDominos Domino[] jeu; // le jeu de dominos // méthode dinstance + String jeuDominosToString() { String s = ""; for( Domino d : this.jeu ) { s += d.dominoToString(); } return s; } +JeuDominos() // le constructeur Il reste à prévoir comment le jeu de dominos pourra être construit. Le tableau de dominos étant une variable dinstance, laccès se fait à laide de this Créer une classe spécifique pour contenir un ensemble de dominos sous la forme dun tableau. Ici, class JeuDominos par exemple Créer une classe spécifique pour contenir un ensemble de dominos sous la forme dun tableau. Ici, class JeuDominos par exemple Encapsuler le tableau de dominos dans la classe comme variable dinstance. Ici, Domino[] jeu Encapsuler le tableau de dominos dans la classe comme variable dinstance. Ici, Domino[] jeu Doter la classe des méthodes dinstance utiles. Ici, public String jeuDominosToString() Doter la classe des méthodes dinstance utiles. Ici, public String jeuDominosToString()
10 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Solution : classe JeuDominos jeu:Domino[] // le tableau de dominos // Méthodes dinstance qui crée un jeu public void createJeuNormal() { this.jeu = new Domino[28](); int n = 0; for( int m1=0 ; m1<=6 ; m1++) for( int m2=i ; m2<=6 ; m2++) // Placer un nouveau domino de // marque m1,m2 à la position n this.jeu[n++] = new Domino(m1,m2); } +jeuDominosToString():String // Constructeur dun jeu vide public JeuDominos() { this.jeu = new Domino[0]; } Construire un jeu de dominos vide pour commencer Plusieurs solutions sont envisageables mais ici on préfèrera procéder ainsi : Tableau vide (ZERO éléments) On aurait aussi pu vouloir écrire : this.jeu = null; mais la méthode jeuDominosToString() naurait pas fonctionnée correctement dans le cas où le jeu naurait pas encore été créé. On aurait aussi pu vouloir écrire : this.jeu = null; mais la méthode jeuDominosToString() naurait pas fonctionnée correctement dans le cas où le jeu naurait pas encore été créé. Ajouter une méthode dinstance qui crée un un jeu de dominos. Ex: public void createJeuNormal() Ajouter une méthode dinstance qui crée un un jeu de dominos. Ex: public void createJeuNormal()
11 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Complément : Pour donner la possibilité de connaître facilement le nombre de dominos du jeu, on peut ajouter une nouvelle méthode dinstance. Il ne reste quà utiliser cette classe dans un applicatif. classe JeuDominos // le tableau de dominos jeu:Domino[] // Méthodes dinstance +createJeuNormal():void +jeuDominosToString():String // Méthodes dinstance qui fournit // le nombre actuel de dominos du jeu public int size() { return this.jeu.length; } // Constructeur dun jeu vide +JeuDominos() Ajouter une méthode dinstance qui fournit le nombre de dominos du jeu. Ex: public int size() Ajouter une méthode dinstance qui fournit le nombre de dominos du jeu. Ex: public int size() Cela permet déviter davoir à accéder au tableau de dominos depuis lextérieur de cette classe, en faisant :.jeu.length
12 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Applicatif : On veut construire puis afficher un jeu de dominos classe JeuDominos // Variable dinstance jeu:Domino[] // Méthodes dinstance +createJeuNormal():void +jeuDominosToString():String +size():int // Constructeur dun jeu vide +JeuDominos() classe MainDominos +$ main(String[]) { test1(); } +$ test1() { } JeuDominos jeuNormal = new JeuDominos(); jeuNormal.createJeuNormal(); System.out.println( "Jeu contenant " + jeuNormal.size() + " dominos"); System.out.println(jeuNormal.jeuDominosToString()); Créer un jeu de dominos vide Ajouter des dominos au jeu Afficher le nombre de dominos du jeu Afficher tous les dominos du jeu Au final, on saperçoit que la classe MainDominos na plus besoin daccéder directement au tableau de dominos (qui se trouve maintenant dans le jeu) Ceci constitue une bonne pratique dans le paradigme Orienté-Objet ! Utilisations des méthodes dinstance de la classe JeuDominos
13 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde OBJECTIFS DU PARADIGME ORIENTÉ-OBJET Ce que nous venons de mettre en œuvre est en parfait accord avec lobjectif du paradigme Orienté-Objet : Un problème étant posé : le décomposer en plusieurs petites entités plus simples (classes) : => faire apparaître des classes dobjets bien ciblées >>> leurs donner le maximum dautonomie (en évitant quelles délèguent à dautres ce quelles peuvent faire) >>> leurs permettre dêtre manipulées extérieurement le plus facilement possible (en les dotant de méthodes dinstance utiles à la résolution globale) résoudre le problème global posé en faisant interagir ces entités entre elles : => ici, il ne sagit plus que de manipuler les entités depuis lextérieur
14 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Quel est le champ dutilisation des classes encapsulant des tableaux ? Dans lexemple traité (un jeu de dominos), nous navons fait que construire un jeu de dominos. Mais pour jouer aux dominos, il faudrait penser à : la création de la pioche la distribution de dominos aux joueurs la constitution de la ligne de jeu UN JEU EN COURS Ce qui revient à partager le jeu initial en sous-ensembles de dominos de tailles variables la pioche (taille décroissante) la donne des joueurs (taille variable) la ligne de jeu (taille croissante)
15 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS Lorsque la taille des ensembles dobjets est variable, cela induit un ASPECT DYNAMIQUE. Cet aspect dynamique complique la gestion des tableaux car ceux-ci sont des STRUCTURES DE DONNÉES STATIQUES. les classes encapsulant des ensembles dobjets de taille variable ont donc pour travail de rendre dynamique une structure de donnée normalement statique. La pioche perd 3 dominos pioche = new Domino[14-3] La pioche perd 3 dominos pioche = new Domino[14-3] La donne contient 2 dominos de plus donne = new Domino[4+3-1] La donne contient 2 dominos de plus donne = new Domino[4+3-1] La ligne de jeu gagne 1 domino ligneDeJeu = new Domino[4+1] La ligne de jeu gagne 1 domino ligneDeJeu = new Domino[4+1]
16 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS De quelles méthodes faudrait-il disposer pour que les classes qui encapsulent des ensembles dobjets variables soient facilement utilisables de lextérieur ? classe Pioche // Variable dinstance laPioche:Domino[] // Méthodes dinstance +piocheToString():String // Constructeur de pioche vide Pouvoir créer une pioche vide (constructeur) Pouvoir ajouter un domino à la pioche Pouvoir ajouter plusieurs dominos en une fois Pouvoir tester si la pioche est vide Pouvoir connaître le nombre de dominos de la pioche Pouvoir piocher un domino aléatoirement Lexemple de la pioche +Pioche() +add(Domino d):void +add(Domino[] setDominos):void +isEmpty():boolean +size():int +piocheUnDomino():Domino Il ne reste quà écrire ces méthodes dinstance On se basera sur un constructeur qui initialise la variable dinstance à null (fait pendant le cours)
17 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS classe DonneJoueur // Variable dinstance laDonne:Domino[] // Méthodes dinstance +donneToString():String // Constructeur de donne vide Pouvoir créer une donne vide (constructeur) Pouvoir ajouter un domino à la donne Cest le jeu de dominos qui pourrait distribuer les dominos aux joueurs Pouvoir ajouter plusieurs dominos en une fois Idem mais en fournissant tous les dominos dun coup (par exemple) Pouvoir tester si la donne est vide Ce peut être utile pour savoir si le joueur a gagné (le jeu doit terminer) Pouvoir connaître le nombre de dominos de la donne Pouvoir extraire un domino choisi par son rang Ce peut être utile pour permettre au joueur de jouer un certain domino Pouvoir extraire un domino choisi par sa référence Idem mais en désignant le domino par sa référence dobjet Pouvoir faire jouer le joueur sur la base dune pioche et dune ligne de jeu Cette méthode permettrait à un joueur de « demander » à sa donne de jouer un domino relativement à une pioche et une ligne de jeu Pouvoir retrouver le plus grand domino jouable Cette méthode permettrait dadopter une stratégie de jeu qui tente de jouer le plus gros domino de la donne compte tenu dune ligne de jeu etc. Lexemple de la donne des joueurs +DonneJoueur() +add(Domino d):void +add(Domino[] setDominos):void +isEmpty():boolean +size():int +extractDomino(int ind):Domino +extractDomino(Domino d):Domino +joueUnDomino(Pioche pioche, LigneDeJeu ldj):boolean +getDominoMaxValueToPlay(LigneDeJe u ldj):Domino Etc.
18 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS classe LigneDeJeu // Variable dinstance ldj:Domino[] // Méthodes dinstance +donneToString():String // Constructeur de donne vide Pouvoir créer une ligne de jeu vide (constructeur) Pouvoir ajouter un domino à droite de la ligne de jeu Permet aux joueurs dajouter un domino à droite dune la ligne de jeu Pouvoir ajouter un domino à gauche de la ligne Idem mais à gauche Pouvoir tester si la ligne de jeu est vide Ce peut être utile pour savoir si on doit jouer un double (début de jeu) Pouvoir connaître le nombre de dominos de la donne Pouvoir connaître un domino choisi par son rang Peut être utile pour permettre au joueur dadopter une stratégie de jeu Pouvoir connaître un domino choisi par sa référence Idem mais en désignant le domino par sa référence dobjet Savoir si un domino est jouable à droite de la ligne de jeu Permettrait à un joueur de « demander » à la ligne de jeu si un certain domino peut y être accolé à droite Savoir si un domino est jouable à droite de la ligne de jeu Idem mais à gauche etc. Lexemple de la ligne de jeu +DonneJoueur() +addToRight(Domino d):boolean +addToLeft(Domino d):boolean +isEmpty():boolean +size():int +getDomino(int ind):Domino +getDomino(Domino d):Domino +isAccolableToRight(Domino d):boolean +isAccolableToLeft(Domino d):boolean Etc.
19 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS A travers ces exemples, on voit apparaître des classes dotées de méthodes dinstance dont le rôle est de fournir des fonctionnalités utiles aux objets qui les instancient. Les trois classes ensemblistes (Pioche, Donne et LigneDeJeu) doivent interagir entre car elles participent à un même objectif de jeu. Chacune représente une part du programme de jeu de dominos. A la base, la classe JeuDominos devrait instancier une pioche, une ligne de jeu et des joueurs, eux-mêmes instanciant leur propre donne. Finalement, la classe JeuDominos jouent le rôle de chef dorchestre pour lapplication. Au départ, cest delle que (1) le jeu sera construit puis que (2) le jeu se déroulera en délégant aux autres objets la plupart des fonctionnalités du jeu : 1 objet JeuDominos1 objet LigneDeJeu 1 objet Pioche 1 table de Joueurs 1 objet Donne 1 objet Joueur contient
20 retours Rechercher le meilleur coup (en utilisant la pioche, la ligne de jeu et en utilisant une stratégie éventuel- lement définie par le joueur) Rechercher le meilleur coup (en utilisant la pioche, la ligne de jeu et en utilisant une stratégie éventuel- lement définie par le joueur) Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde (A) CLASSE ENCAPSULANT UN TABLEAU DOBJETS On voit ici tout lintérêt du premier concept de lOrienté-Objet : Les objets encapsulent des données et des méthodes agissant sur leurs données A partir de là, il est possible de déléguer les fonctionnalités aux objets qui savent le mieux les réaliser. Pour que le jeu se déroule, cest de la classe JeuDominos quune méthode dinstance devra faire jouer les joueurs à tour de rôle jusquà la fin de la partie. Mais le fait de jouer un coup sera délégué à chaque joueur. Et enfin, la délégation se poursuit vers la donne, la pioche et la ligne de jeu. Faire jouer les joueurs à tour de rôle (simple boucle qui délègue aux joueurs le fait de jouer en leur donnant une pioche et une ligne de jeu) Faire jouer les joueurs à tour de rôle (simple boucle qui délègue aux joueurs le fait de jouer en leur donnant une pioche et une ligne de jeu) Faire jouer ce joueur (en donnant une pioche et une ligne de jeu) Faire jouer ce joueur (en donnant une pioche et une ligne de jeu) délégation retour délégation 1 objet Donne 1 objet JeuDominos1 objet LigneDeJeu 1 objet Pioche 1 table de Joueurs 1 objet Joueur 1 objet Donne retour contient
21 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde PROTECTION DE LÉTAT INTERNE DES OBJETS Jusquà présent nous avons laissé libre laccès à létat des objets depuis lextérieur. Si cela semble pratique, cest en réalité très dangereux et va à lencontre du paradigme Orienté-Objet. - Pourquoi cela est-il dangereux ? Lorsquune classe possède ou reçoit un objet externe, elle peut vouloir modifier directement létat de lobjet sans passer par une de ses méthodes dinstance. Un joueur qui possède une donne pourrait modifier les dominos quelle contient !?! Un joueur qui connaît la pioche pourrait en profiter pour piocher les dominos qui lintéressent !?! - Cela serait-il un problème ? On pourrait dire que « non » puisque, si le code était fait de sorte quun joueur puisse piocher les dominos qui lintéressent, cela se produirait pour TOUS les joueurs. Tout au plus, le programme tricherait mais, trichant pour tous les joueurs, il y aurait peu dintérêt à écrire une tel programme.
22 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde PROTECTION DE LÉTAT INTERNE DES OBJETS - Quel est donc le vrai problème ? En fait, il sagit plus dun problème de bonne conception des programmes. Dans le paradigme OO, ce que lon désire avant tout cest de structurer les programmes de sorte quils soient facile à écrire, à comprendre, à corriger, à maintenir et à faire évoluer. Or, si lon effectue de lextérieur une partie des comportements normalement attendus dans une classe, il va vite devenir difficile de repérer tous les endroits où des modifications peuvent survenir sur un objet. Lécriture, la lecture, la correction, la maintenance et lévolution en seront dautant plus ardues. - Quel est le point de vu de lOO ? Le paradigme OO nous incite à respecter un point fondamental : « ne pas faire faire à un objet ce quun autre saurait mieux faire » Le joueur na pas à piocher directement dans la pioche, il doit utiliser une méthode dinstance de la pioche La pioche ne doit pas déléguer le fait de piocher On peut aussi dire : ne pas déléguer à dautres ce que lon sait faire mais ne pas faire ce que dautres feraient mieux. Seule la pioche doit permettre de piocher un domino pour assurer que cela est bien fait aléatoirement ! Seule la ligne de jeu peut accepter un domino à lune de ses extrémités pour assurer que le domino est jouable ! Une autre interprétation serait de dire : - concevoir les objets en leur donnant le plus dautonomie possible (le fait quune partie du comportement attendu pour un objet doive être traité extérieurement est le signe dun manque dautonomie de lobjet ; la classe de cet objet na pas été correctement conçue) - nutiliser les objets quau travers de leurs méthodes dinstance (en respectant lusage des méthodes dinstance des objets, on évite déparpiller les traitements et on respecte lautonomie des objets)
23 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde PROTECTION DE LÉTAT INTERNE DES OBJETS sss - Comment y remédier ? En OO, on devrait toujours protéger létat interne des objets dun accès extérieur. Pour cela : On peut déclarer comme privées les variables dinstance. On utilise pour cela le mot réservé « private ». Ex: private int m1, m2; On doit aussi faire en sorte que les classes dobjets fournissent suffisamment de méthode dinstance pour leur permettre dêtre facilement et totalement manipulés depuis lextérieur.
24 Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Acta est fabula