1°/ mise en place de l'abstraction

  • Dans le TP 2, la méthode rencontre() de la classe Humain est normalement vide et redéfinie dans Homme et Femme.
  • Cela implique que cette méthode devrait être déclarée abstraite.
  • Dans le même ordre d'idée, si on respecte totalement l'esprit POO, isHomme() et isFemme() ne peuvent être définis au niveau de Humain et sont donc normalement abstraits.

 

  • Modifiez les classes du TP 2 pour rendre abstrait tout ce qui devrait l'être.
 

2°/ Classement avec expression lambda


  • Dans le TP 2, l'entête de Humain a été modifiée pour que la classe implémente l'interface Comparable :
class Humain implements Comparable<Humain> {
...
 
  • De plus, la méthode compareTo() a été définie directement dans Humain et Homme (voire dans Femme pour le tri multi-critère)

 

  • Cette façon de faire fige totalement les critère possibles de tri, en l'occurrence sur l'âge et le salaire.
  • Fort heureusement, la méthode Collections.sort() peut prendre en paramètre un objet de type Comparator, c'est-à-dire une interface fonctionnelle.
  • Il est donc possible de passer en paramètre de sort() une expression lambda, définissant la méthode compare(T o1, T o2) de l'interface Comparator.
  • Exemple pour trier par longueur croissante une liste de String :
List<String> lst = new ArrayList<>();
... // remplir la liste

Collections.sort(lst, (s1, s2) -> s1.length() - s2.length() )
  • l'EL renvoie la différence de longueur, donc une valeur entière négative, nulle ou positive selon que s1 est plus petit, égal ou plus grand que s2. Cela correspond à la signature et au comportement attendu de la méthode compare().

 

  • L'exercice consiste à supprimer les méthodes compareTo() des classes existantes et, à la fin d'un tour de jeu, d'utiliser successivement sort() et une EL pour :
    • trier la population par âge décroissant,
    • trier la population avec les femmes/filles d'abord et ensuite les hommes/garçons,
    • trier la population par âge croissant et pour chaque âge, les femmes/filles d'abord et les hommes/garçons ensuite,
    • trier la population avec les femmes/filles d'abord et ensuite les hommes/garçons, et pour chaque sexe, trier par âge croissant
    • trier la population par âge croissant et pour chaque âge, les femmes/filles d'abord et les hommes/garçons ensuite, avec de plus un tri sur les femmes par fertilité croissante et les hommes par salaire croissant.

 

3°/ Création d'interface fonctionnelles.

 

3.1°/ prendre du poids en vieillissant

  • Quand les humains vieillissent, ils grossissent.
  • Cependant, le code qui modifie leur poids est écrit "en dur", dans les méthodes vieillir(). Il est donc en l'état impossible de changer ce code, à moins de le réécrire et recompiler l'application.
  • En revanche, si on crée une IF avec une méthode représentant la modification du poids, on pourrait modifier vieillir() et rencontre() afin de prendre en paramètre une telle IF et ainsi pouvoir modifier dynamiquement la façon de grossir avec l'âge.

 

  • Créer une IF comme suivant :
@FunctionalInterface
interface Aging {
   public void gainWeight(Humain h);
}
  • Dans Humain, Homme et Femme, ajouter à vieillir() un paramètre du type Aging,
  • Dans Homme et Femme, à la place des morceaux de code qui modifient le poids, appeler la méthode gainWeight() avec en paramètre l'objet courant.
  • Dans Population, ajouter à vieillir() un paramètre du type Aging et dans la boucle qui parcourt les humains, appeler la méthode vieillir() avec ce paramètre.
  • Dans le moteur du jeu, appeler la méthode vieillir() de Population en fournissant comme paramètre une EL dont le comportement reproduit la modification de poids qui était à l'origine dans le TP 1.

 

3.2°/ prendre du poids avec les rencontres

  • Mettre en place la même chose pour rencontre() que pour vieillir() est un peu plus compliqué. En effet, la prise de poids s'effectue sur 2 objets (l'humain courant et l'humain passé en paramètre) et de plus, elle n'est pas identique selon que c'est un homme qui rencontre une femme ou l'inverse.
  • A vous de trouver une solution à base d'IF+EL pour reproduire le comportement d'origine du TP 1, sans avoir de code "en dur" modifiant le poids dans les méthodes rencontre()

 

3.3°/ fertilité impactée par la taille de la population.

  • Utiliser une solution à base d'IF+EL pour qu'à la fin d'un tour de jeu, lorsque la population vieillit, les femmes ont une fertilité qui est impactée par la taille de la population actuelle :
    • si cette taille est entre 0 et 20, on garde la fertilité telle quelle,
    • si cette taille est entre 21 et 50, on augmente la fertilité de 2,
    • si cette taille est supérieure à 50, on diminue la fertilité de 1.

 Remarque finale : ce TP devrait montrer aussi bien le côté pratique des ELs que le fait qu'il ne faut pas en abuser. En effet, essayer de rendre un maximum de fonctionnalités configurables à souhait via des ELs à tendance à rendre le code moins lisible et plus compliqué (cf. exo 3.2 et 3.3) alors qu'en faisant simplement des méthodes avec quelques paramètres, on obtient certes moins de possibilités, mais c'est plus simple à coder et relire.