Aller au contenu principal

Atelier 14 - Catalogue de jeux vidéo

Créez un programme Java qui gère un catalogue de jeux vidéo en utilisant les interfaces fonctionnelles Supplier, Consumer, Predicate et les conteneurs Optional.

Spécifications

1. Enum Genre

Créez un enum Genre avec les valeurs : ACTION, RPG, SPORT, SIMULATION, PUZZLE, INCONNU.

2. Classe JeuVideo

Créez une classe JeuVideo avec les attributs suivants :

  • titre (String)
  • genre (Genre)
  • prix (double)
  • note (double) — entre 0.0 et 10.0
  • multijoueur (boolean)

Redéfinissez toString() pour afficher :

[GENRE] Titre — $prix (Note : note/10)

3. Catalogue

Dans le main, créez une ArrayList<JeuVideo> avec au moins 10 jeux couvrant différents genres, prix et notes.

4. Supplier — Fabrique de valeurs

4a. Jeu par défaut

Créez un Supplier<JeuVideo> nommé jeuParDefaut qui retourne un jeu inconnu avec des valeurs neutres. Vous l'utiliserez dans la section 8 avec Optional.orElseGet().

4b. Générateur de code promotionnel

Créez un Supplier<String> nommé codePromo qui génère un code aléatoire de 6 caractères alphanumériques (lettres majuscules et chiffres) à chaque appel.

Utilisez ce fournisseur pour associer un code promotionnel aux 3 jeux les plus chers du catalogue et affichez-les sous le format :

The Witcher 3 [RPG] — Code promo : A7K2XP

5. Predicate — Filtres

Créez les prédicats suivants :

NomCondition
estPopulairenote > 7.5
estAbordableprix < 30.0
estMultijoueurmultijoueur == true
estRPGgenre == Genre.RPG

Composez ensuite un prédicat combiné bonPlanMulti : populaire et abordable et multijoueur.

Créez la méthode utilitaire suivante et utilisez-la pour afficher les résultats de chaque filtre :

static void afficherFiltre(ArrayList<JeuVideo> catalogue, Predicate<JeuVideo> filtre, String titre)

6. Consumer — Affichage et traitement

Définissez une méthode statique afficher(JeuVideo jeu) qui affiche un jeu avec le préfixe ">> ".

Créez ensuite les consommateurs suivants en référençant des méthodes existantes :

  1. afficherJeu — référence à la méthode statique afficher
  2. afficherAvecCode — affiche le titre du jeu suivi d'un code promo généré à la volée (combinaison du Consumer et du Supplier<String> de la section 4b) :
    The Witcher 3 — Code promo : B3ZT9W
    FIFA 25 — Code promo : Q1MP4R

Utilisez afficherJeu avec forEach pour afficher le catalogue au complet après les tris.

7. Références de méthodes

Intégrez les autres formes de références de méthodes dans votre programme :

7a. Référence à une méthode d'instance existante

Utilisez System.out::println directement avec forEach pour afficher le catalogue.

7b. Référence à une méthode de l'instance reçue

Triez le catalogue par titre avec Comparator.comparing en référençant JeuVideo::getTitre, puis affichez le résultat.

7c. Référence à un constructeur

Créez un Supplier<ArrayList<JeuVideo>> en référençant le constructeur d'ArrayList, obtenez une nouvelle liste, copiez-y le catalogue et affichez sa taille.

8. Optional — Recherche sécurisée

Écrivez la méthode utilitaire suivante :

static Optional<JeuVideo> chercherParTitre(ArrayList<JeuVideo> catalogue, String titre)

Utilisez-la dans les trois scénarios ci-dessous :

Scénario A — Jeu trouvé

Cherchez un titre qui existe. Affichez-le avec ifPresent() en lui passant le Consumer afficherJeu (référence de méthode — voir section 6).

Scénario B — Jeu absent avec valeur de secours

Cherchez un titre qui n'existe pas. Utilisez orElseGet() avec jeuParDefaut pour obtenir un jeu de remplacement et affichez-le.

Ne pas utiliser orElse() ici — utiliser orElseGet().

Scénario C — Jeu absent avec exception

Cherchez un titre qui n'existe pas. Utilisez orElseThrow() avec un Supplier<RuntimeException> pour lancer une exception descriptive. Gérez-la avec un bloc try/catch et affichez le message d'erreur.

Exemple d'exécution attendu

=== Catalogue complet ===
>> [ACTION] God of War — $39.99 (Note : 9.5/10)
>> [RPG] The Witcher 3 — $19.99 (Note : 9.7/10)
>> [SPORT] FIFA 25 — $69.99 (Note : 6.8/10)
...

=== Codes promo — 3 jeux les plus chers ===
FIFA 25 [SPORT] — Code promo : A7K2XP
Hogwarts Legacy [RPG] — Code promo : M3BV1Q
Cyberpunk 2077 [RPG] — Code promo : ZT9WR4

=== Jeux populaires (note >= 8.0) ===
[ACTION] God of War — $39.99 (Note : 9.5/10)
[RPG] The Witcher 3 — $19.99 (Note : 9.7/10)
...

=== Bons plans multijoueur (populaire + abordable + multijoueur) ===
[PUZZLE] Among Us — $5.99 (Note : 8.2/10)
...

=== Catalogue trié par titre ===
>> [PUZZLE] Among Us — $5.99 (Note : 8.2/10)
...

=== Taille de la copie : 10 ===

=== Recherche : "The Witcher 3" ===
>> [RPG] The Witcher 3 — $19.99 (Note : 9.7/10)

=== Recherche : "Pong 2077" (absent — valeur de secours) ===
>> [INCONNU] Inconnu — $0.0 (Note : 0.0/10)

=== Recherche : "Ghost Game" (absent — exception) ===
Erreur : Jeu introuvable dans le catalogue.

Contraintes

  • Supplier doit être utilisé pour la génération de codes et comme source de valeur par défaut dans orElseGet()
  • orElseGet(Supplier) doit être utilisé au lieu de orElse(valeur) dans le scénario B
  • ifPresent() doit recevoir un Consumer
  • orElseThrow() doit recevoir un Supplier<RuntimeException>
  • La méthode afficherFiltre doit prendre un Predicate<JeuVideo> en paramètre
  • Aucun null ne doit apparaître dans le code — toute absence de valeur passe par Optional
  • Les Consumer doivent être définis comme variables et réutilisés (pas écrits en ligne à chaque appel)
  • Consumer<JeuVideo> afficherJeu doit être défini via une référence à une méthode statique
  • Le tri de la section 7b doit utiliser Comparator.comparing avec une référence de méthode

Questions de réflexion

  • Quelle est la différence entre orElse(valeur) et orElseGet(Supplier) ? Pourquoi préférer orElseGet() si la valeur par défaut est coûteuse à créer ?
  • Pourquoi Supplier est-il utile pour la création d'objets « à la demande » plutôt que de les créer à l'avance ?
  • Un même Consumer<JeuVideo> peut-il être passé à la fois à forEach et à ifPresent ? Pourquoi ?
  • Pourquoi orElseThrow() prend-il un Supplier<RuntimeException> plutôt que directement une exception ?
  • Quelle est la différence entre une référence à une méthode statique (Classe::méthode) et une référence à une méthode de l'instance reçue (Classe::méthode) ? Comment Java fait-il la distinction ?