À partir de maintenant, nous allons utiliser Eclipse (lancer la commande eclipse dans un terminal) comme environnement pour faire les TPs. Installez-le sur votre machine et familiarisez-vous avec son utilisation.
Créer un projet nommé TP4.
Vérifier que l'environnement d'exécution est bien Java-23, changer si ce n'est pas le cas.
Écrire une classe Main qui affiche Hello Eclipse.
Raccourcis et astuces
Que fait sysout + Ctrl + Space dans un main ?
Que fait toStr + Ctrl + Space dans une classe ?
Définir un champs foo de type int, que fait get + Ctrl + Space, et set + Ctrl + Space .
Dans le menu Source, comment générer un constructeur initialisant le champ foo ?
Sélectionner le nom de la classe puis Alt + Shift + R, qu'obtient-on ? Même question avec le champ foo .
Écrire a = 2 + 3 + 4, puis sélectionner 2 + 3 puis Alt + Shift + L .
Écrire new Integer(2), en gardant le curseur après ')', appuyer sur Ctrl + 1, que se passe-t-il ?
Déclarer une variable s de type String et cliquer sur String en maintenant la touche Ctrl . Que se passe-t-il ?
Dans la méthode toString(), que fait un Ctrl + Clic sur super.toString() ?
Sélectionner le champs foo, puis Ctrl + Shift + G. Que se passe-t-il ?
À quoi sert Ctrl + Shift + O ?
À quoi sert Ctrl + Shift + C ?
Apprenez les raccourcis que nous venons de voir, cela vous fera gagner du temps lors des TPs notés.
On souhaite écrire une classe Library pour modéliser une bibliothèque et permettant de stocker des livres.
On veut que le code suivant fonctionne :
var library = new Library(); library.add(book); System.out.println(library.findByTitle("Da Vinci Code"));
Vous utiliserez le record Book suivant
public record Book(String title, String author) { public Book { Objects.requireNonNull(title); Objects.requireNonNull(author); } @Override public String toString() { return title + " by " + author; } }Avec Eclipse, faire un copier-coller du code ci-dessus dans le répertoire src (oui, ça fonctionne !).
javap -c Library.class
L'implantation faite dans l'exercice précédent est lente si la méthode findByTitle est appelée fréquemment. On va changer l'implantation en gardant la même API, c'est à dire avec les mêmes méthodes publiques (ayant les mêmes signatures). De cette façon, il ne sera pas nécessaire de changer le code du main !
var library2 = new Library(); library2.add(new Book("Da Vinci Code", "Dan Brown")); library2.add(new Book("Angels & Demons", "Dan Brown")); library2.removeAllBooksFromAuthor("Dan Brown");
Dans cet exercice, nous allons voir sur un exemple concret ce que l'on entend par encapsulation. Pour cela, on revient sur le dernier exercice du TP précédent.
Considérons le code suivant qui est une solution possible pour l'exercice Rogue du TP précédent. Dans cette version, le concept de prix est complètement encapsulé dans la classe Price. La classe RogueEncapsulated n'a pas besoin de savoir comment les prix sont représentés, elle peut utiliser la classe Price sans savoir comment elle est implémentée.
Pour comprendre la puissance de l'encapsulation, nous allons rajouter un des pièces de cuivre avec la convention qu'une pièce d'argent vaut 25 pièces de cuivre.
Modifier l'implémentation de la classe Price pour qu'elle représente des prix en or, argent et cuivre. Vous ne toucherez pas au code de la classe RogueEncapsulated et tout devra fonctionner de la même façon sauf que les prix seront maintenant exprimés en or, argent et cuivre.
import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; public record Price(int silverTotal){ public static final int SILVER_PER_GOLD = 13; public Price { if (silverTotal < 0){ throw new IllegalArgumentException("Invalid price."); } } public Price(int gold, int silver){ this(gold * SILVER_PER_GOLD + silver); } private int gold(){ return silverTotal / SILVER_PER_GOLD; } private int silver(){ return silverTotal % SILVER_PER_GOLD; } @Override public String toString(){ return gold() +"g and " + silver() + "s"; } public static Price randomBelow(Price cost){ Objects.requireNonNull(cost); var rng = ThreadLocalRandom.current(); return new Price(rng.nextInt(cost.silverTotal)); } public boolean isLowerThan(Price other){ Objects.requireNonNull(other); return silverTotal < other.silverTotal; } public Price substract(Price other){ Objects.requireNonNull(other); if (isLowerThan(other)){ throw new IllegalArgumentException("Not enough gold pieces."); } return new Price(silverTotal - other.silverTotal); } }
import java.util.Scanner; public class RogueEncapsulated { public static String ask(Scanner scanner){ while(true){ System.out.println("Type yes (to buy), no (to skip) or quit (to leave)"); var choice = scanner.nextLine(); if (choice.equals("yes") || choice.equals("no") || choice.equals("quit")){ return choice; } System.out.println("Invalid choice, please try again."); } } public static void main(String[] args) { var purse = Price.randomBelow(new Price(100, 0)); var scanner = new Scanner(System.in); var potions = 0; while (true) { System.out.println("You have " + purse + " gold pieces."); var price = Price.randomBelow(new Price(10, 0)); System.out.println("Do you want to buy a potion of healing for " + price +"?"); var choice = ask(scanner); if (choice.equals("quit")){ break; } if (choice.equals("no")){ continue; } // buy potion if (purse.isLowerThan(price)){ System.out.println("You don't have enough gold pieces."); continue; } potions++; purse = purse.substract(price); } System.out.println("You manage to acquire " + potions + " potions with " + purse + " gold pieces remaining."); } }