Cours BUT Info

Ch. 0 bis — Rappels de POO et tests

Objets, classes, encapsulation, héritage, interfaces, classes abstraites, transtypage et tests JUnit 5 — les prérequis du S2 remis au propre.

Ce qu'on est censé déjà savoir

Prérequis du S2

  • Développement orienté objet : classes, objets, visibilité, encapsulation, interfaces, héritage, classes abstraites, UML
  • Qualité de développement : outils (VSCode → IntelliJ, Git), tests, documentation, exceptions

Les langages à objets en 4 caractéristiques

  1. Toute chose est un objet (à part les types primitifs en Java) ;
  2. Un programme = des objets qui se disent quoi faire (envoi de messages) ;
  3. Chaque objet a un type précis (sa classe) ;
  4. Tous les objets d'un type reçoivent les mêmes messages → c'est la base du polymorphisme.

L'objet : identité, état, comportement

PropriétéC'est quoiComment on la manipule
IdentitéCe qui le distingue de tout autre objet== (et pas equals()) ; deux copies d'un livre restent 2 objets
ÉtatSes donnéesStocké dans les attributs
ComportementCe qu'il sait faireDéfini par les méthodes

La classe

Une classe définit ce qui est commun à tous ses objets :

  • la nature et le nombre des attributs, le comportement (méthodes) ;
  • comment les objets sont initialisés (constructeur) — en Java, pas de destructeur ;
  • la création d'instances via new.

Encapsulation

Mettre un objet d'une autre classe en attribut pour réutiliser tout ou partie de ses méthodes (méthodes déléguées). L'objet délégué n'est généralement pas visible depuis l'extérieur de la classe.

Héritage

Une hiérarchie de similarité : deux Employé ont plus en commun que deux Humain — la description se spécialise en descendant. C'est le même principe que la taxonomie du vivant, et en Java, Object en est la racine.

Object
└── Humain
    └── Employé
        ├── Étudiant
        └── Enseignant

Une sous-classe :

  • hérite des attributs et méthodes de sa super-classe ;
  • peut ajouter des caractéristiques ;
  • peut redéfinir des méthodes pour étendre le comportement.

Règle d'or de la redéfinition

Une redéfinition devrait a priori toujours faire un appel à super pour ne pas perdre le comportement hérité.

Substituabilité

Une sous-classe peut toujours être utilisée à la place de sa super-classe : toutes les méthodes de la classe sont appelables sur les objets des sous-classes. C'est ce qui rend le polymorphisme possible.

Interfaces

Un contrat sur les méthodes : la signature des méthodes que les classes devront implémenter.

  • Méthodes systématiquement public, pas d'attributs ;
  • Contournement de l'héritage simple : une classe peut implémenter plusieurs interfaces (ce n'est pas de l'héritage multiple — les méthodes ne sont pas héritées de l'interface — mais ça permet un « polymorphisme multiple ») ;
  • Une interface peut dériver d'une autre interface ;
  • Lien avec la notion d'API : ce qui peut être utilisé.
Exemple de hiérarchie
interface Collection<E> {
    boolean add(E e);
    boolean contains(E e);
    int size();
}
interface List<E> extends Collection<E> { E get(int idx); }
class ArrayList<E> implements List<E> { /* ... */ }

Classes abstraites : l'entre-deux

Une classe abstraite définit une partie de son comportement et déclare des méthodes abstraites que les sous-classes devront implémenter.

  • Outil de factorisation du code ;
  • Pas de new directement (mais constructeur possible, en protected) ;
  • Une sous-classe concrète doit implémenter toutes les méthodes abstraites.
Exemple Vehicule
abstract class Vehicule {
    protected int prix;
    protected double vitesseMax;
    protected int nbKm;
    public abstract int getCoutConso(); // à définir par chaque fille
}
class Voiture extends Vehicule {
    private double coutConsoAuKm;
    @Override public int getCoutConso() { /* calcul voiture */ return 0; }
}
class Velo extends Vehicule {
    @Override public int getCoutConso() { return 0; } // quasi nul à la pompe
}

Transtypage (cast)

Le type déclaré d'une variable ne correspond pas toujours à son type réel — c'est une conséquence directe de la substituabilité. Exemple JavaFX : une List<Node> peut contenir des Button ou des Label.

Upcasting (vers le haut)

List<Node> lst;
lst.add(new Label("test"));   // Label traité comme un Node : automatique, sans risque

Downcasting (vers le bas)

List<Node> lst;
if (lst.get(1) instanceof Label) {
    Label label = (Label) lst.get(1);
    label.setText("bla");
}
  • À faire seulement si on est sûr du type réel ;
  • Nécessaire pour appeler une méthode qui n'existe que dans la sous-classe ;
  • Le cast reste dans une même hiérarchie d'héritage : ce n'est pas un mécanisme de conversion de données (int i = (int) "123"; est invalide).

instanceof : mauvaise pratique

L'idée du polymorphisme, c'est précisément de ne pas avoir à connaître le type réel de l'objet. Si vous multipliez les instanceof, repensez votre conception.

Tests : JUnit 5

Librairie de test Java (version 5), l'équivalent des XUnit dans les autres langages.

« Never in the field of software development was so much owed by so many to so few lines of code. » — Martin Fowler

Les 4 phases d'un test

Set-up (optionnel) — créer le contexte du test : l'objet à tester, les données nécessaires

Exercise — exécuter la méthode à tester avec des données prédéfinies

Verify — vérifier le résultat par rapport à une valeur attendue

Tear-down (optionnel) — libérer les ressources utilisées

Mise en œuvre JUnit 5
import org.junit.jupiter.api.*;

class MaClasseTest {
    @BeforeEach
    public void setup() { /* Set-up */ }

    @Test
    public void testXY() { /* Exercise + Verify */ }

    @AfterEach
    public void teardown() { /* Tear-down */ }
}

ch0bis-rappels.pdf

R3 04-cours-0bis-Rappels.pdf · 22 diapositives

Consultation seule — téléchargement désactivé

Chargement du document…

Dernière mise à jour le

Sur cette page