310 likes | 443 Views
Objectifs de ce cours (I21). Classes et objets simples Découpage structurel et fonctionnel Modularité fonctionnelle, robustesse et maintenance. Classes et objets simples sans méthode Méthodes d’instance simples Plus à propos de Java Classes et Objets ensemblistes
E N D
Objectifs de ce cours (I21) Classes et objets simples Découpage structurel et fonctionnel Modularité fonctionnelle, robustesse et maintenance • Classes et objets simples sans méthode • Méthodes d’instance simples • Plus à propos de Java • Classes et Objets ensemblistes • Classes encapsulant des tableaux d’objets (1) • Classes génériques à spécialiser (3) Résumé du cours précédent Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
(B) CLASSES GÉNÉRIQUES À SPÉCIALISER:TreeMap<K,V> La classe générique TreeMap<K,V> TreeMap<K,V> se spécialise à l’aide de 2 noms de classes d’objets : une classe qui représente les clés K etune autre des valeurs V Itération sur un dictionnaire ①Pour itérer sur les clés K, utiliser la méthode keySet() : ② Pour itérer sur les valeurs V, utiliser la méthode values() : TreeMap<ISBN,Livre> dicLivres = new TreeMap<ISBN,Livre>(); // ajout de livres dans le dictionnaire ... dicLivres.put(unIsbn,unLivre)... // Itération sur les clés du dictionnaire for (ISBN isbn :dicLivres.keySet()){ System.out.println(isbn.isbnToString()); } TreeMap<ISBN,Livre> dicLivres = new TreeMap<ISBN,Livre>(); // ajout de livres dans le dictionnaire ... dicLivres.put(unIsbn,unLivre)... // Itération sur les valeurs du dictionnaire for (Livre livre :dicLivres.values()){ System.out.println(livre.livreToString()); } Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
(B) CLASSES GÉNÉRIQUES À SPÉCIALISER:TreeMap<K,V> Ordonnancement de dictionnaires à l’aide de l’interface Comparable<K> Exemple : // Implémentation de l’interface Comparable par la classe ISBN : public class ISBN implements Comparable<ISBN> { // METHODE à IMPLEMENTER dans la CLASSE intcompareTo ( ISBN isbn ) { if ( isbnToString() < isbn.isbnToString() ) return -1; if ( isbnToString() == isbn.isbnToString() ) return 0; return +1; } // ...autres variables et méthodes de la classe... } Déclaration d’implémentation de l’interface Comparable<K> Méthode de l’interface devant être implémentée (à ajouter à la classe) Implémentation simpliste à revoir ! Maintenant, on peut créer un dictionnaire de livres basé sur des clés ISBN. Exemple : TreeMap<ISBN,Livre> dicLivres = new TreeMap<ISBN,Livre>(); Sinon, la plupart des classes du JDK implémentent déjà l’interface Comparable<K>. On peut donc les utiliser directement comme des clés pour des dictionnaires. Exemples : TreeMap<Integer,Joueur> dicJoueurs = new TreeMap<Integer,Joueur>(); TreeMap<String,Livre> dicLivres = new TreeMap<String,Livres>();
Objectifs de ce cours (I21) Classes et objets simples Découpage structurel et fonctionnel Modularité fonctionnelle, robustesse et maintenance • Classes et objets simples sans méthode • Méthodes d’instance simples • Plus à propos de Java • Compléments Java • Classes et Objets ensemblistes • Modélisation en POO Maintenant ! Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Premiers éléments de modélisation en POO ❶ Repérage des classes candidates élémentaires On part du problème posé (à la manière d’un cahier des charges) et exposé dans son domaine spécifique (sciences exactes, sciences expérimentales ou sciences humaines). On repère les entités élémentaires qui doivent être manipulées. Ce seront les premières classes candidates (ex: Domino, Livre, ISBN, Place). ❷ Repérage des classes candidates complémentaires de type ensembliste En général, les traitements devront manipuler des ensembles de données. On peut alors envisager plusieurs autres classes candidates de type ensembliste (ex: Pioche, LigneDeJeu, Donne, Bibliotheque, Graphe, Chemin). ❸ Repérage des classes candidates englobantes Il faudra généralement prévoir au moins une classe principale qui englobe/regroupe les entités du problème et à partir de laquelle les traitements sont initiés(ex: JeuDominos, Bibliotheque, Graphe) ❹ Repérage des classes candidates résultantes Parfois, il est également utile de prévoir une ou plusieurs classes qui engloberont les données résultantes fabriquées (ex: GrapheChemins) Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des données propres à chaque classe Une fois que l’on dispose des grandes classes permettant de modéliser le problème, il faut affiner la modélisation en descendant au niveau interne des classes. ❺ Modélisation des données propres à chaque classe • On commence à préciser les variables d’instances et éventuellement de classe. • En parallèle, il faut aussi prévoir : • leurs niveaux extérieur de visibilité (spécificateurs d’accès public ou private) • et leur caractère mutable ou non (final). classe Domino ➠ private int m1, m2; Cette déclaration ne permet de modification des marques qu’à partir de méthodes d’instance Mais elle ne permet pas à l’utilisateur d’accéder aux marques depuis l’extérieur. classe Domino ➠ public final int m1, m2; Cette déclaration fige les marques du domino après constructionEt elle permet à l’utilisateur d’y accéder directement depuis l’extérieur classe Domino ➠ public int m1, m2; // cette déclaration est dangereuse ! Cette déclaration permet à l’utilisateur de modifier les marques du dominos comme bon lui semble depuis l’extérieur de l’objet. Plus rien ne lui interdit de donner un état incohérent au domino. Par exemple : le domino (-54, 64831) ! Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des données propres à chaque classe Règle à observer : dans un souci de plus grande autonomie des objets, il faut toujours protéger le plus possible les variables d’instance et de classe • Si la variable ne doit plus changer de valeur après la construction : • si on juge que l’état de la variable peut intéresser l’utilisateur de l’objet, déclarer public final • sinon, toujours déclarer private final ✪ Une variable est dite sensible pour un objet quand l’état global de l’objet peut être rendu incohérent si la valeur de la variable était changée arbitrairement depuis l’extérieur • Si la variable doit pouvoir changer de valeur après la construction : • si l’état de la variable est sensible pour l’objet✪ : • toujours déclarer private • si l’état de la variable n’est pas sensible pour l’objet : • si on juge que l’état de la variable peut intéresser l’utilisateur de l’objet, déclarer public • sinon, toujours déclarer private Au final, il convient de bien choisir la déclaration des variables en fonction de ce que l’on veut faire ! Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des données propres à chaque classe Alors, private ou public final ? Si, ayant fait une déclaration private, on désire quand même que l’utilisateur accède à l’état de la variable, on a toujours la possibilité de créer des « méthodes getters »! ☺accès à l’aide de GETTERS : ☺accès DIRECT sans getter : public class Domino { private int m1, m2; public Domino( int m1, int m2) { this.m1 = m1; this.m2 = m2; } // Méthodes getters public int getM1() { return this.m1; } public int getM2() { return this.m2; } ... public void retourne() { int m = this.m1; this.m1 = this.m2; this.m2 = m; } } // Par ailleurs (en dehors de la classe Domino) Domino d1 = new Domino(2,5); if (d1.m1 == 3 )... // accès direct INTERDIT ! d1.m1 = 3; // affectation INTERDITE ! if (d1.getM1() == 3 )... // accès par getter OK public class Domino { public final int m1, m2; public Domino( int m1, int m2) { this.m1 = m1; this.m2 = m2; } ... } // Par ailleurs (en dehors de la classe Domino) Domino d1 = new Domino(2,5); if (d1.m1 == 3 )... // accès direct OK d1.m1 = 3; // affectation INTERDITE! if (d1.getM1() == 3 ) ... Seule cette version permettra de sécuriser le domino tout en pouvant le retourner (méthode qui échange les 2 marques) pour l’insérer dans une ligne de jeu Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des données propres à chaque classe Attention aux constructeurs et getters/setters alliés aux déclarations private ! Lorsqu’un getter retourne un type primitif ou un objet immutable, il n’y a pas de problème car la variable retournée est soit recopiée, soit constante. Mais lorsqu’un getter retourne une variable objet mutable, celle-ci pourra être modifiée en dehors. Et cela revient presque à donner un accès public à la variable ! ☠GETTER retournant un objet mutable ! public class PointCouleur { private int x, y; private Couleur c; public PointCouleur( int x, int y, Couleur c){ this.x = x; this.y = y; this.c = c; } // Méthodes getters public int getX() { return this.x; } public int getY() { return this.y; } public Couleur getCouleur() { return this.c; } ... } public class Couleur { private int r, v, b; public Couleur( int r, int v, int b){ this.r = r; this.v = v; this.b = b; } // Méthodes getters public int getR() { return this.r; } ... // Méthodes setters public void setR(int r) { this.r = r; } ... } // Par ailleurs (en dehors des classes) Couleur c1 = new Couleur(255,0,0); PointCouleur p1 = new PointCouleur(2,5,c1); PointCouleur p2 = new PointCouleur(3,6,c1); // la couleur du point peut être changée p1.getCouleur().setV(255); //...grâce au getter !!! c1.setB(255); //...et même sans le getter !!! Le PointCouleur ne sait pas que sa couleur (pourtant privée) a été changée ! Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde Les PointCouleur p1 et p2 partagent la même couleur !
Modélisation des données propres à chaque classe Solution pour les déclarations private accompagnées de getters/setters • Lorsqu’un getter retourne un objet mutable, il faudra toujours : • construire une copie de la variable objet fournie à la construction • utiliser une copie de la variable objet dans les getters et les setters Classe qui expose un type objet (sa couleur) à protéger à la construction et des getters/setters ☺GETTER et objet mutable correct public class PointCouleur{ privateint x, y; private Couleur c; public PointCouleur( int x, int y, Couleur c){ this.x = x; this.y = y; this.c = new Couleur(c.getR(),c.getV(),c.getB()); } // Méthodes getters public intgetX() { return this.x; } public intgetY() { return this.y; } public Couleur getCouleur() { return new Couleur(this.c.getR(), this.c.getV(), this.c.getB());} ... // Méthodes setters public voidsetX(int x) { this.x = x; } ... public voidsetCouleur(Couleur c) { this.c = new Couleur(this.c.getR(), this.c.getV(), this.c.getB());} } public class Couleur { private int r, v, b; public Couleur( int r, int v, int b){ this.r = r; this.v = v; this.b = b; } // Méthodes getters public int getR() {return this.r;} ... // Méthodes setters public void setR(int r) {this.r = r;} ... } Classe inchangée car n’exposant que des types primitifs Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des données propres à chaque classe Fort heureusement, la classe String est IMMUTABLE ! Étant immutables (une fois un objet String construit, il ne peut être modifié), les String peuvent être librement utilisés dans les getters/setters et dans les constructeurs sans que cela ne pose de problème. ☺GETTER retournant un objet immutable ☺accès DIRECT à un objet immutable final public class Joueur { private String nom; public Joueur( String nom){ this.nom = nom; } // Méthode getter public String getNom(){return this.nom;} ... } public class Joueur { public final String nom; public Joueur( String nom){ this.nom = nom; } ... } Ici, une fois qu’un joueur a été construit avec un nom, il ne peut plus en changer. Les deux déclarations produisent les mêmes comportements (en l’absence de setter à gauche). Par contre, la classe StringBuffer est MUTABLE ! • En Java, la classe StringBuffer permet de construire des chaînes de caractères petit à petit dans un même objet. On dispose de nombreuses méthodes qui retournent souvent l’objet initial de sorte à pouvoir les enchaîner : • public StringBuffer append(<type>) • public StringBuffer insert( int index, <type>) • public StringBuffer delete( int indexStart, int indexEnd) • public char charAt(int index) • int indexOf(String str) où <type> est char, boolean, int, double, ..., String, StringBuffer http://java.sun.com/javase/6/docs/api/java/lang/String.html http://java.sun.com/javase/6/docs/api/java/lang/StringBuffer.html Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des comportements des objets On continue la modélisation en l’affinant au niveau interne par la définition des comportements. ❻ Modélisation des comportements des objets Les comportements des objets représentent la partie à laquelle il faut apporter le plus de soin. Une classe qui ne fournirait pas les comportements attendus serait non seulement incorrecte mais, en plus, elle rendrait toutes les autres incorrectes vis-à-vis du paradigme Orienté Objets. Cela parce que, pour palier à l’insuffisance de la classe, il serait nécessaire de prévoir des comportements dans d’autres classes où il ne serait pas normal qu’ils s’y trouvent. Et, au bout du compte, il faudra reprendre non pas UNE mais PLUSIEURS classes ! Mais quels sont les comportements attendus pour une classe donnée ? C’est exactement la question qu’il faut se poser pour chaque classe ! En POO, l’ensemble des objets sont en interactions mais chacun réalise une partie spécifique du problème global. À partir de là, il faut et il suffit que chaque classe offre toutes les méthodes utiles pour permettre de lui faire faire ce qu’elle doit faire. En même temps, une classe peut elle-même en utiliser d’autres pour l’aider à réaliser sa partie mais il s’agit ici de délégation. Une classe doit déléguer à d’autres ce qu’elles savent mieux faire. La délégation est donc justement ce qui réalise les interactions entre classes. Mais la délégation a à voir avec l’algorithmique, pas avec la recherche des méthodes utiles à une classe donnée. Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Modélisation des comportements des objets ☛ Par exemple, un jeu de cartes (classe JeuCartes) doit permettre de construire des jeux de 32, 34, 52 ou 54 cartes. Il faut donc prévoir des constructeurs en conséquence. ☛ Par ailleurs, il faudra aussi construire chaque carte (classe Carte) mais le jeu de cartes ne proposera pas d’ajouter de nouvelles cartes. Il pourra fonctionner comme un talon qui fournit la carte du dessus ou reçoit une carte en dessous, etc. ☛ Ensuite, pour faire des réussites – par exemple la réussite Joséphine ou la réussite Horloge – il faudra disposer de classes spécifiques (classes ReussiteJoséphine et ReussiteHorloge). Ces classes ne proposeront pas de construire le jeu de cartes, il devra être automatiquement construit par la classe de la réussite choisie. Par contre, chaque classe de réussite devra au moins proposer des méthodes qui permettent de faire progresser la réussite d’un pas, de simuler une réussite d’un coup ou d’afficher un état intermédiaire de la réussite, etc. ☛ D’autres classes seront utiles comme nous l’avons vu, par exemple la classe PlateauCartes qui prendra en charge la disposition des cartes sur le plateau de jeu et qui fournira quelques compor-tements utiles comme de remplir le plateau avec un talon de cartes, de savoir si une carte donnée se trouve accessible sur le plateau, de retrouver la dernière carte d’une colonne ou d’une ligne, etc. La modélisation des comportements consiste à mettre de l’ordre dans : « qui doit faire quoi ? » ou « qui doit proposer quoi ? » Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Nous allons nous intéresser à un problème de recherche de plus courts chemins pour aller d’un point à un autre. Simplement à partir de là, nous allons construire un modèle OO qui permette de répondre à ce type de problématique. Pour modéliser le problème, nous devons commencer par définir les entités les plus évidentes. Si nous voulons aller d’un point à un autre, il faudra nécessairement définir des emplacements que nous pourrons éventuellement nommer. ☛ appelons-les des places et envisageons une classe Place Ensuite, interrogeons-nous sur ce que sera un lien d’une place à l’autre. S’il doit exister des chemins plus courts que les autres, il faut nécessairement que d’une place on puisse se rendre à plusieurs autres. Il faudra donc, pour chaque place, tenir une liste des places atteignables directement. De plus, l’éloignement entre deux places doit être quantifiable. Pour simplifier, décidons qu’il s’agira d’une donnée entière. ☛ appelons cette mesure la valuation d’une place à une autre et envisageons un type primitif int voire une classe IntegerTiens ! Ce n’est pas une nouvelle classe ! Maintenant que nous avons des places liées les unes aux autres, nous devons envisager de disposer d’un ensemble de places. Ensemble à l’intérieur duquel nous chercherons des chemins. Si nous représentons un tel ensemble, nous allons nous apercevoir qu’il a la forme d’un graphe. ☛ appelons-le ainsi et envisageons une classe Graphe Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
“C” “D” “E” “A” “B” “F” “C” “D” “A” “B” “F” “E” “B” “A” “C” “A” “B” “C” “D” “E” “F” “F” “D” “E” Un exemple de modélisation en POO À ce point, faisons une petite digression pour mieux nous représenter ce qu’est un graphe. • Par exemple, le schéma suivant représente un graphe : • de 6 places nommées de "A" à "F » • avec 8 liaisons • et où chaque place a de 2 à 4 liaisons Maintenant, voyons un graphe simple (graphe où les places ont au maximum 2 liens) : Dans ce cas, la recherche du plus court chemin est très simplifiée ! Ce dernier graphe peut nous permettre de revoir la représentation du précédent en choisissant des chemins linéaires et en les plaçant pareillement en ligne droite. Si le chemin contient toutes les places, il ne devrait rester qu’à ajouter quelques liens supplémentaires pour terminer sinon il faudra encore y ajouter les places manquantes. LA FORME DONNÉE À UN GRAPHE N’EST QUE PEU SIGNIFICATIVE TOUS LES GRAPHES BLEUS SONT IDENTIQUES Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Poursuivons notre modélisation Si nous voulons trouver des chemins, il faudra aussi prévoir comment représenter ces chemins. Par définition, un chemin ne sera qu’une liste ordonnée de places aussi nous avons le choix entre : soit utiliser directement un ArrayList<Place> en tant que variable d’instance là où c’est utile,(ce choix convient lorsqu’il n’y a qu’un endroit où utiliser des chemins et qu’il n’y a que très peu de méthodes spécifiques les concernant, généralement de simples itérations sur leurs éléments) soit définir une classe spécifique – la classe Chemin – qui, encapsulant un ArrayList<Place>, permettra de fournir des méthodes utiles à la manipulation de chemins.(ce choix conviendra lorsqu’il y aura au moins une méthode importante à implémenter ou qu’il faille utiliser des chemins à plusieurs endroits du programme) Nous choisirons la seconde méthode en pensant au fait qu’il sera utile de déterminer la valuation totale d’un chemin et que cela n’est pas si trivial qu’on puisse ne pas le proposer. ☛ envisageons une classe Chemin Maintenant, sachant qu’il n’y aura pas toujours un unique chemin plus court que les autres mais qu’il pourra y en avoir plusieurs, il faut se poser la question de l’utilité d’une classe ensembliste de chemins(le problème est le même que précédemment avec ses 2 choix possibles, soir directement un ArrayList<Chemin>, soit une classe Chemins qui encapsule un ArrayList<Chemin>). Or, si plusieurs chemins sont envisageables, il faudra bien quelques méthodes pour nous aider à trouver celui que nous préférons. ☛ envisageons une classe Chemins Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Poursuivons notre modélisation : qu’en sera-t-il des classes englobantes et résultantes ? D’évidence, la classe Graphe sera la classe englobante de notre applicatif puisque nous n’aurons qu’à construire un graphe et à en obtenir des chemins. ☛ soit la classe englobante Graphe Mais puisqu’il nous sera éventuellement fourni plusieurs chemins, il serait bon de disposer d’une classe résultante qui contiendra tout ce qu’il faut pour filtrer les chemins et choisir celui qui nous conviendra le mieux. Nous avons déjà prévu une telle classe, la classe Chemins. Comme il s’agit maintenant d’une classe résultante, nous en profiterons pour y insérer un peu plus d’informations qu’une simple liste de chemins. Par exemple, nous pourrons référer au graphe et aux places de départ et d’arrivée des chemins. Rebaptisons-là sous le nom de GrapheChemins. ☛ soit la classe résultante GrapheChemins Ce devrait être tout pour cette étape de recherche des entités de modélisation du problème ! Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Finalement, voici nos classes : Finalement, voici nos classes : une classe Place qui représente un emplacement et possède des liens valués vers d’autres places une classe Graphe qui connaît toutes les places une classe Chemin qui contient les places de départ, intermédiaires et d’arrivée une classe GrapheChemins qui contient une liste de chemins relative à un graphe et à un trajet voulu Poursuivons notre modélisation Il convient d’affiner la modélisation en descendant au niveau interne des classes à commencer par définir les données propres à chaque classe puis en définissant leurs comportements Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
La place “B”qui est liéeà 4 places “A” “F” “B” “E” “C” Un exemple de modélisation en POO La classe Place La classe Place représente un emplacement et possède des liens valués vers d’autres places ❏ Chaque place sera représenté par un nom. De plus, une place n’aura pas à changer de nom mais celui-ci devra être accessible. ☛ soit la variable d’instance public final String nom ❏ Pour les liens vers les autres places, un ArrayList<Place> serait suffisant mais il faut aussi définir les valuations entre places. Or, chaque liaison doit être valuée à l’aide d’une donnée entière (égale à l’unité par défaut) qu’il faudra pouvoir retrouver sur la base d’une place. On peut donc penser à un dictionnaire dont les clés seraient les places. Soit un dictionnairede valuations rangées par les places, i.e. un TreeMap<Place,Integer>(puisqu’il n’est pas possible d’utiliser un type primitif int). ☛ soit la variable d’instance private TreeMap<Place,Integer> mapValuations // *********************************************************************** // Variables d'instance // *********************************************************************** /**Nomdelaplace(lenomd'uneplacedoitêtreuniquedansungraphe).*/ publicfinal String nom; /** *Dictionnairedesvaluationsdesplacesliées(pardéfaut,lesvaluations *sontégalesàl'unité). */ privateTreeMap<Place,Integer> mapValuations; Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Le grapheexemple quipossède un dictionnaire de 6 places “A” “A” “B” “B” “C” 《 , , , , , 》 “C” “F” “D” “E” “F” “D” “E” Un exemple de modélisation en POO La classe Graphe La classe Graphe connaît toutes les places ❏ Un graphe doit simplement posséder une liste de places (par ailleurs toutes liées entre elles). Un simple ArrayList<Place> suffirait a priori mais, si l’on pense à la construction du graphe, comme il faudra ajouter les places une à une, il peut être intéressant de prévoir une liste qui permette de savoir facilement si une place de même nom n’existe pas déjà. On s’orientera donc vers un dictionnaire de places rangées par leurs noms. ☛ soit la variable d’instance private TreeMap<String,Place> mapOfPlaces // *********************************************************************** // Variables d'instance // *********************************************************************** /**Dictionnairedesplacesdugrapheaccessiblesselonleursnoms(String).*/ private TreeMap<String,Place> mapOfPlaces; Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe Chemin La classe Chemin qui contient les places de départ, intermédiaires et d’arrivée ❏ Un chemin est simplement représenté par une liste ordonnée de places. Il devra au moins contenir deux places – de départ et d’arrivée – et éventuellement d’autres places intermédiaires. De plus, chaque place devra être directement joignable depuis la précédente. Un simple ArrayList<Place> suffit donc. ☛ soit la variable d’instance private ArrayList<Place> allPlaces // *********************************************************************** // Variables d'instance // *********************************************************************** /** Lesplacesordonnéesdecechemin;considérévidetantqu'ilnecontient *aucuntrajet(i.e.aumoinsdeuxplaces).*/ privateArrayList<Place> allPlaces; Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe GrapheChemins La classe GrapheChemins qui contient une liste de chemins relative à un graphe et à un trajet voulu • ❏ Comme il s’agit de l’unique classe résultante de l’applicatif, nous y mettrons suffisamment d’informations pour la rendre autonome. Ainsi, une fois récupéré un tel objet, on disposera de toutes les informations utiles pour en interpréter les résultats. Elle contiendra : • une liste de chemins sous la forme d’une ArrayList<Chemin> • la référence au graphe rattaché à cette liste de chemins • la place de départ • la place d’arrivée • Seule la liste de chemins, devant être construite au fur et à mesure, sera déclarée private. • Les autres données seront publicfinal. // *********************************************************************** // Variables d'instance // *********************************************************************** /**Legrapherattachéàcettelistedechemins.*/ publicfinal Graphe graphe; /**Laplacededépartrattachéeàcettelistedechemins.*/ publicfinal Place placeFrom; /**Laplaced'arrivéerattachéeàcettelistedechemins.*/ publicfinal Place placeTo; /**Lalistedescheminsmenantdelaplacededépartàlaplaced'arrivée.*/ private ArrayList<Chemin> allChemins; Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Poursuivons notre modélisation Il ne reste qu’à définir les comportements de chaque classe Une bonne manière de faire est de partir de la classe englobante À ce niveau, il ne s’agit que de définir les méthodes principales car on ne peut pas encore savoir exactement toutes les méthodes qui s’avèreront utiles. Certaines n’apparaîtrons qu’à l’implémentation. Mais, dans un esprit généraliste, on proposera tout de suite plusieurs versions (surchargées) de certaines méthodes même s’il s’avèrera qu’elles ne seront pas toutes utilisées. Cette manière de faire permet de mieux cerner la spécificité des classes sans toutefois en restreindre trop l’étendue. En effet, en prévoyant un maximum de méthodes, on donne à la fois une grande étendue et une forte spécificité aux classes. Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe Graphe Quand nous construirons une place, il ne sera pas toujours possible de définir tous les liens vers les autres places car certaines pourront ne pas encore exister. Pour faire simple, on proposera donc de construire d’abord toutes les places puis, ensuite seulement, de définir les liens des places entre elles. ❏ Au départ, on voudra construire un graphe vide. ☛ public Graphe() ❏ Ensuite, on devra insérer des places les unes après les autres ☛ publicboolean addPlace(String nomPlace)// place fournie par son nom ☛ publicboolean addPlace(Place place)// place fournie directement ❏ Puis, on définira leurs liaisons et leurs valuations ☛ publicboolean addLiaison(String place1, String place2) // valuation par défaut ☛ publicboolean addLiaison(String place1, String place2, int valuation) ❏ On prévoira aussi des méthodes d’informations ☛ publicboolean hasPlace(String nomPlace) // cet nom de place existe-t-il déjà ? ☛ publicboolean hasPlace(Place place) // cette place existe-t-elle déjà ? ☛ publicboolean isConsistant() // le graphe est-il consistant ? Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe Graphe (suite) ❏ On prévoira des méthodes d’informations générales ☛ publicint getNombrePlaces()// nombre de places total ☛ publicint getNombreLiaisons()// nombre de liaisons total ☛ publicdouble getValuationMoyenne() // la valuation moyenne totale ❏ On prévoira aussi une méthode de représentation textuelle du graphe ☛ public String toString() ❏ Enfin, il faudra bien sûr prévoir une méthode qui fournira tous les chemins d’une place de départ à une place d’arrivée (on réservera le filtrage du plus court chemin dans l’objet résultant obtenu) ☛ public GrapheChemins getAllChemins(String placeDepart, String placeArrivee) Les méthodes fournies en plusieurs versions (surchargées) sont en général simples à écrire car il suffit de détailler la plus générale d’entre elles, toutes les autres s’y ramenant. Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe Place ❏ Puisque cette classe est utilisée comme clé dans son TreeMap<Place,Integer>, elle devra implémenter l’interface Comparable<Place> ☛ publicint compareTo(String nomPlace) ❏ On voudra construire une place par son nom. ☛ public Place(String nomPlace)// quel est le nom de cette place ? ❏ Puis, on définira ses liaisons et ses valuations avec d’autres places ☛ publicboolean addLiaison(String place1, String place2) // valuation par défaut ☛ publicboolean addLiaison(String place1, String place2, int valuation) ❏ On prévoira des méthodes d’informations ☛ publicString getNom() // quel est le nom de cette place ? ☛ publicboolean hasLiaison(Place placeLiee) // cette liaison existe-t-elle déjà ? ☛ publicint getValuationWithPlace(Place placeLiee) // la valuation de la liaison ❏ On prévoira des méthodes d’informations générales ☛ publicint getNombreLiaisons() // nombre de liaisons total ☛ public Set<Place> getSetOfPlacesLiees() // les places liées à celle-ci ❏ On prévoira aussi une méthode de représentation textuelle de la place ☛ public String toString() Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe Chemin ❏ On voudra construire un chemin vide en spécifiant la place de départ. ☛ public Chemin(Place placeFrom)// chemin vide (pas encore de trajet) ❏ Puis, on définira ses liaisons et ses valuations avec d’autres places ☛ publicbooleanadd(Place place) // ajout d’une place en queue de chemin ❏ On prévoira des méthodes d’informations ☛ publicbooleancontains(String nomPlace) // ce nom de place est-il déjà joint ? ☛ publicbooleancontains(Place place) // cette place est-elle déjà jointe ? ☛ publicPlace getLastPlace() // la valuation de la liaison ❏ On prévoira des méthodes d’informations générales ☛ public Place getNombrePlaces() // nombre de places total ☛ public Place getValuationTotale() // valuation totale du chemin ☛ public Place getPlaceFrom() // quelle est la place de départ ? ☛ public Place getPlaceTo() // quelle est la place d’arrivée ? ☛ publicArrayList<Place> getAllPlaces() // la liste des places de ce chemin ❏ On prévoira aussi une méthode de représentation textuelle de la place ☛ public String toString() Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO La classe GrapheChemins ❏ On voudra construire une liste de chemins vide rattachée à un graphe et un trajet (départ/arrivée). ☛ publicGrapheChemins(Graphe graphe, Place placeFrom, Place placeTo) ❏ Puis, on définira ses liaisons et ses valuations avec d’autres places ☛ publicbooleanaddCheminComplet(Chemin chemin) // ajouter un chemin complet ❏ On prévoira des méthodes d’informations générales ☛ publicbooleanisValide() // les données de base sont-elles valides ? ☛ publicArrayList<Chemin> getAllChemins() // tous les chemins ☛ publicArrayList<Chemin> getAllPlusCourtsChemins() // + les plus courts ☛ publicArrayList<Chemin> getAllPlusCourtsCheminsMinEtapes() // + minimum étapes ❏ On prévoira aussi une méthode de représentation textuelle de la liste des chemins ☛ public String toString() ❏ Enfin, il pourra prévoir une méthode qui fournira tous les chemins de la place de départ à la place d’arrivée (cette méthode pourra être appelée par le graphe qui dispose d’une méthode identique) ☛ publicGrapheCheminsconstructAllChemins() Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple de modélisation en POO Une fois la modélisation réalisée, il faut résumer les directives importantes en vu de l’implémentation. • Les places doivent avoir un nom unique (ni nul ni vide) dans les graphes. • Les graphes doivent contenir des places toutes liées entre elles (de sorte à pouvoir aller de n’importe quelle place à n’importe quelle autre). • Les listes de places des chemins doivent être maintenues ordonnées et chaque place doit posséder une liaison directe vers la place suivante (sauf la dernière). • Les listes de chemins ne doivent contenir que des chemins complets (i.e. qui vont de la place de départ à la place d’arrivée). • Etc. Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Un exemple d’implémentation Enfin, il ne reste plus qu’à procéder à l’implémentation. Cette étape est du ressort du programmeur. Son rôle est d’assurer la cohérence interne des objets en prenant soin de traiter tous les cas qui peuvent se présenter (références nulles ou invalides dans les paramètres fournis...). public classGraphe { // Variables d'instance /**Dictionnairedesplacesdugrapheaccessiblesselonleursnoms(String).*/ privateTreeMap<String,Place> mapOfPlaces; // Constructeur publicGraphe() {// construction d’un graphe vide this.mapOfPlaces = newTreeMap<String,Place>(); } // Méthodes d'instance publicbooleanaddPlace(String nomPlace) {// ajout d’une place fournie par son nom returnaddPlace(new Place(nomPlace)); } publicbooleanaddPlace(Place place) {// ajout d’une place fournie directement boolean ok = false; if ( place != null) { String nom = place.getNom(); if ( !nom.isEmpty() && !this.mapOfPlaces.containsKey(nom) ) { this.mapOfPlaces.put(nom, place); ok = true; } } return ok; } } On utilise la méthode surchargée (plus générale) en délégant à la classe Place sa construction. On s’assure que la place soit un objet valide On s’assure qu’elle a un nom et qu’il n’existe pas encore dans le graphe Maintenant, on peut l’ajouter au graphe Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde
Acta est fabula Cours JAVA (I21) -Licence 1 Semestre 2 / Y.Laborde