CodeGym /Cours /JAVA 25 SELF /Exemples de construction d’abstractions dans des cas réel...

Exemples de construction d’abstractions dans des cas réels

JAVA 25 SELF
Niveau 19, Leçon 3
Disponible

1. L’abstraction dans les applications réelles : pourquoi en a-t-on besoin

Dans les cours précédents, nous avons déjà fait connaissance avec la notion d’abstraction et examiné des exemples simples. Voyons maintenant comment cette approche fonctionne dans des tâches plus réalistes. Dans les projets réels, on doit presque toujours traiter avec des objets différents mais similaires. Par exemple, différents moyens de paiement, différents types de transport, différentes formes dans un éditeur graphique. Sans abstraction, le code devient rapidement un ensemble de « if-else » et de copier-coller. Avec l’abstraction — tout est ordonné, élégant et, surtout, pratique pour l’évolution et la maintenance.

L’abstraction permet de :

  • Cacher les détails d’implémentation : travailler avec des objets via une interface commune, sans se soucier de leur fonctionnement interne.
  • Éviter la duplication de code : le comportement et les champs communs sont extraits dans une classe de base.
  • Étendre facilement le système : l’ajout de nouveaux types d’objets ne nécessite pas de réécrire l’ancien code.
  • Rendre le code flexible : on peut remplacer une implémentation par une autre sans modifier le reste du système.

Examinons quelques exemples de domaines différents.

2. Exemple 1 : Systèmes de paiement

Énoncé du problème

Supposons que vous écriviez un module pour une boutique en ligne. Votre tâche est d’implémenter le traitement de différents types de paiements : carte bancaire, PayPal, cryptomonnaie. Ils doivent tous « traiter un paiement », mais chacun a ses propres détails.

Abstraction : classe Payment

public abstract class Payment {
    protected double amount;

    public Payment(double amount) {
        this.amount = amount;
    }

    // Méthode abstraite : la façon de traiter le paiement est décidée par les sous-classes
    public abstract void process();

    // Méthode commune à tous les paiements
    public void printAmount() {
        System.out.println("Montant du paiement : " + amount + " EUR");
    }
}

Implémentations concrètes

public class CreditCardPayment extends Payment {
    private String cardNumber;

    public CreditCardPayment(double amount, String cardNumber) {
        super(amount);
        this.cardNumber = cardNumber;
    }

    @Override
    public void process() {
        System.out.println("Traitement du paiement par carte : " + cardNumber);
        // Ici, on pourrait intégrer une banque :)
    }
}
public class PaypalPayment extends Payment {
    private String email;

    public PaypalPayment(double amount, String email) {
        super(amount);
        this.email = email;
    }

    @Override
    public void process() {
        System.out.println("Traitement du paiement PayPal pour le compte : " + email);
        // Et ici — appel de l’API PayPal
    }
}
public class CryptoPayment extends Payment {
    private String walletAddress;

    public CryptoPayment(double amount, String walletAddress) {
        super(amount);
        this.walletAddress = walletAddress;
    }

    @Override
    public void process() {
        System.out.println("Traitement du paiement crypto vers le portefeuille : " + walletAddress);
        // Ici, il pourrait y avoir la magie de la blockchain
    }
}

Utilisation de l’abstraction

import java.util.*;

public class PaymentDemo {
    public static void main(String[] args) {
        List<Payment> payments = new ArrayList<>();
        payments.add(new CreditCardPayment(1500.0, "1234 5678 9012 3456"));
        payments.add(new PaypalPayment(500.0, "user@example.com"));
        payments.add(new CryptoPayment(0.05, "0xABCD..."));

        for (Payment payment : payments) {
            payment.printAmount();
            payment.process();
            System.out.println("---");
        }
    }
}

Résultat :

Montant du paiement : 1500.0 EUR
Traitement du paiement par carte : 1234 5678 9012 3456
---
Montant du paiement : 500.0 EUR
Traitement du paiement PayPal pour le compte : user@example.com
---
Montant du paiement : 0.05 EUR
Traitement du paiement crypto vers le portefeuille : 0xABCD...
---

Avantages :

  • On peut ajouter un nouveau moyen de paiement sans modifier l’ancien code (par exemple, Apple Pay).
  • Le code qui travaille avec les paiements ne dépend pas de leur type concret.
  • La logique commune (par exemple, l’impression du montant via printAmount()) est implémentée en un seul endroit.

3. Exemple 2 : Transport

Énoncé du problème

Dans un jeu ou un simulateur, vous avez différents types de transport : voitures, vélos, trains. Ils peuvent tous « se déplacer », mais de manières différentes. Certains nécessitent du ravitaillement, d’autres non.

Abstraction : classe Transport

public abstract class Transport {
    protected String name;

    public Transport(String name) {
        this.name = name;
    }

    public abstract void move();

    // Tous les transports n’ont pas besoin de ravitaillement, mais par défaut — non
    public void fuelUp() {
        System.out.println(name + ": ravitaillement non requis.");
    }
}

Implémentations concrètes

public class Car extends Transport {
    public Car(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " roule sur la route.");
    }

    @Override
    public void fuelUp() {
        System.out.println(name + ": on fait le plein d’essence.");
    }
}
public class Bicycle extends Transport {
    public Bicycle(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " pédale.");
    }
    // On ne redéfinit pas fuelUp — un vélo n’a pas besoin de ravitaillement
}
public class Train extends Transport {
    public Train(String name) {
        super(name);
    }

    @Override
    public void move() {
        System.out.println(name + " file sur les rails.");
    }

    @Override
    public void fuelUp() {
        System.out.println(name + ": ravitaillement en diesel ou en électricité.");
    }
}

Utilisation de l’abstraction

import java.util.*;

public class TransportDemo {
    public static void main(String[] args) {
        List<Transport> vehicles = Arrays.asList(
            new Car("Toyota"),
            new Bicycle("Giant"),
            new Train("Express")
        );

        for (Transport t : vehicles) {
            t.move();
            t.fuelUp();
            System.out.println("---");
        }
    }
}

Résultat :

Toyota roule sur la route.
Toyota: on fait le plein d’essence.
---
Giant pédale.
Giant: ravitaillement non requis.
---
Express file sur les rails.
Express: ravitaillement en diesel ou en électricité.
---

Avantages :

  • On peut traiter n’importe quel moyen de transport de la même manière, sans vérifier son type.
  • Facile d’ajouter un nouveau type de transport (par exemple, une trottinette électrique).

4. Exemple 3 : Éditeur graphique

Énoncé du problème

Vous écrivez un mini-éditeur graphique. Il contient des lignes, des ellipses, des polygones — et tout cela sont des « formes » que l’on peut dessiner et redimensionner. Chaque forme implémente ces actions à sa manière.

Abstraction : classe Figure

public abstract class Figure {
    protected String color = "black";

    public abstract void draw();

    public abstract void resize(double factor);

    public void setColor(String color) {
        this.color = color;
    }
}

Implémentations concrètes

public class Line extends Figure {
    private double length;

    public Line(double length) {
        this.length = length;
    }

    @Override
    public void draw() {
        System.out.println("On dessine une ligne de longueur " + length + " de couleur " + color);
    }

    @Override
    public void resize(double factor) {
        length *= factor;
        System.out.println("Nouvelle longueur de la ligne : " + length);
    }
}
public class Ellipse extends Figure {
    private double a, b;

    public Ellipse(double a, double b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public void draw() {
        System.out.println("On dessine une ellipse avec des axes " + a + " et " + b + " de couleur " + color);
    }

    @Override
    public void resize(double factor) {
        a *= factor;
        b *= factor;
        System.out.println("Nouvelles dimensions de l’ellipse : " + a + " x " + b);
    }
}
public class Polygon extends Figure {
    private int sides;

    public Polygon(int sides) {
        this.sides = sides;
    }

    @Override
    public void draw() {
        System.out.println("On dessine un polygone avec " + sides + " côtés de couleur " + color);
    }

    @Override
    public void resize(double factor) {
        System.out.println("On redimensionne le polygone avec " + sides + " côtés à " + factor);
    }
}

Utilisation de l’abstraction

import java.util.*;

public class EditorDemo {
    public static void main(String[] args) {
        List<Figure> figures = new ArrayList<>();
        figures.add(new Line(10));
        figures.add(new Ellipse(5, 3));
        figures.add(new Polygon(6));

        for (Figure f : figures) {
            f.setColor("green");
            f.draw();
            f.resize(2);
            System.out.println("---");
        }
    }
}

Résultat :

On dessine une ligne de longueur 10.0 de couleur green
Nouvelle longueur de la ligne : 20.0
---
On dessine une ellipse avec des axes 5.0 et 3.0 de couleur green
Nouvelles dimensions de l’ellipse : 10.0 x 6.0
---
On dessine un polygone avec 6 côtés de couleur green
On redimensionne le polygone avec 6 côtés à 2.0
---

Avantages :

  • Toutes les formes peuvent être stockées dans une seule liste et traitées de la même manière.
  • Facile d’ajouter une nouvelle forme (par exemple, une étoile ou un cœur).
  • Les méthodes communes (par exemple, définir la couleur via setColor()) sont implémentées une seule fois.

5. Comment l’abstraction aide à simplifier le code

Dans chaque exemple ci-dessus, on retrouve le même schéma :

  • La classe abstraite de base définit le contrat (ce que l’objet sait faire).
  • Les sous-classes concrètes implémentent les détails.
  • Le code qui travaille avec l’abstraction ne dépend pas du type d’objet, ce qui rend le système flexible et extensible.

Tableau comparatif des approches

Sans abstraction (if-else) Avec abstraction (POO)
Beaucoup de conditions selon le type Nouveau type — on modifie le code
Duplication de la logique Logique — en un seul endroit
Difficile à étendre Ajout — facile
Difficile à tester Remplacer les implémentations — facile

6. Erreurs typiques lors de la conception d’abstractions

Erreur n° 1 : L’abstraction pour l’abstraction.
Si vous n’avez qu’un seul type d’objet et qu’aucune extension n’est prévue — une classe abstraite n’est pas nécessaire. Inutile de compliquer le code sans raison.

Erreur n° 2 : Une abstraction trop générale.
Si la classe de base est trop « floue », les sous-classes peuvent n’avoir rien en commun hormis le nom. Par exemple, une abstraction « Thing » pour tout et n’importe quoi. Cela complique la maintenance et la compréhension du code.

Erreur n° 3 : Duplication de code dans les sous-classes.
Si tous les sous-classes ont la même implémentation d’une méthode, il convient de l’extraire dans la classe de base (la rendre non abstraite).

Erreur n° 4 : Violation du principe « du général au particulier ».
Si des détails qui ne concernent qu’une seule sous-classe apparaissent dans la classe abstraite — c’est que l’abstraction est mal choisie.

Erreur n° 5 : Oubli d’implémenter les méthodes abstraites.
Si vous n’implémentez pas toutes les méthodes abstraites dans la sous-classe, le compilateur vous obligera à rendre la classe abstraite elle aussi. Parfois, c’est inattendu :)

1
Mission
JAVA 25 SELF, niveau 19, leçon 3
Bloqué
Calculs de surface dans une application graphique 🎨
Calculs de surface dans une application graphique 🎨
1
Mission
JAVA 25 SELF, niveau 19, leçon 3
Bloqué
Système universel d'envoi de messages 📧💬
Système universel d'envoi de messages 📧💬
1
Mission
JAVA 25 SELF, niveau 19, leçon 3
Bloqué
Gestion de la flotte de l'entreprise 🚚🚲
Gestion de la flotte de l'entreprise 🚚🚲
1
Mission
JAVA 25 SELF, niveau 19, leçon 3
Bloqué
Module de traitement des commandes dans un magasin de détail 🛒
Module de traitement des commandes dans un magasin de détail 🛒
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION