Principes SOLID en Java

khalil la - Feb 26 - - Dev Community

Les principes SOLID sont des bonnes pratiques en programmation orientée objet qui permettent d'avoir un code plus modulaire, maintenable et extensible.

1️⃣ S - Principe de Responsabilité Unique (Single Responsibility Principle - SRP)

Une classe ne doit avoir qu'une seule raison de changer.

❌ Mauvais exemple (Violation du SRP)

Une classe qui gère les informations du salarié et le calcul de la paie :

class Employe {
    private String nom;
    private double salaire;

    public Employe(String nom, double salaire) {
        this.nom = nom;
        this.salaire = salaire;
    }

    public void genererFichePaie() {
        System.out.println("Fiche de paie générée pour " + nom);
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Bon exemple (Respect du SRP)

Séparer les responsabilités :

class Employe {
    private String nom;
    private double salaire;

    public Employe(String nom, double salaire) {
        this.nom = nom;
        this.salaire = salaire;
    }
}

class PaieService {
    public void genererFichePaie(Employe employe) {
        System.out.println("Fiche de paie générée pour " + employe.getNom());
    }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ O - Principe Ouvert/Fermé (Open/Closed Principle - OCP)

Une classe doit être ouverte à l'extension mais fermée à la modification.

❌ Mauvais exemple

Ajouter une nouvelle réduction oblige à modifier le code existant :

class Facture {
    public double calculerRemise(double montant, String typeClient) {
        if (typeClient.equals("VIP")) {
            return montant * 0.9;
        } else if (typeClient.equals("Fidèle")) {
            return montant * 0.95;
        }
        return montant;
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Bon exemple (Respect de l’OCP)

Utilisation du polymorphisme :

interface Remise {
    double appliquerRemise(double montant);
}

class RemiseVIP implements Remise {
    public double appliquerRemise(double montant) {
        return montant * 0.9;
    }
}

class Facture {
    public double appliquerRemise(double montant, Remise remise) {
        return remise.appliquerRemise(montant);
    }
}
Enter fullscreen mode Exit fullscreen mode

3️⃣ L - Principe de Substitution de Liskov (Liskov Substitution Principle - LSP)

Une classe dérivée doit pouvoir remplacer sa classe mère sans effet indésirable.

❌ Mauvais exemple

Un carré est un rectangle qui a ses quatre côtés de même longueur.
Mais, un carré ne peut pas toujours remplacer un rectangle : un carré a un coté et un rectangle a une longueur et une largeur

class Rectangle {
    protected int largeur, longueur;

    public void setLargeur(int largeur) { this.largeur = largeur; }
    public void setLongueur(int longueur) { this.hauteur = longueur; }
}

class Carre extends Rectangle {
    @Override
    public void setLargeur(int largeur) {
        this.largeur = this.longueur = largeur;
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Bon exemple

Utiliser des classes distinctes :

interface Forme {
    int getAire();
}

class Rectangle implements Forme {
    private int largeur, longueur;
    public int getAire() { return largeur * longueur; }
}

class Carre implements Forme {
    private int cote;
    public int getAire() { return cote * cote; }
}
Enter fullscreen mode Exit fullscreen mode

4️⃣ I - Principe de Ségrégation des Interfaces (Interface Segregation Principle - ISP)

Une classe ne doit pas être forcée à implémenter des méthodes inutiles.

❌ Mauvais exemple

Une interface trop large :

interface Oiseau {
    void voler();
    void nager();
}

class Pingouin implements Oiseau {
    public void voler() { throw new UnsupportedOperationException(); }
    public void nager() { System.out.println("Le pingouin nage"); }
}
Enter fullscreen mode Exit fullscreen mode

✅ Bon exemple

Créer plusieurs interfaces :

interface OiseauVolant { void voler(); }
interface OiseauMarin { void nager(); }

class Aigle implements OiseauVolant {
    public void voler() { System.out.println("L'aigle vole"); }
}

class Pingouin implements OiseauMarin {
    public void nager() { System.out.println("Le pingouin nage"); }
}
Enter fullscreen mode Exit fullscreen mode

5️⃣ D - Principe d'Inversion des Dépendances (Dependency Inversion Principle - DIP)

Une classe doit dépendre d’abstractions et non d’implémentations concrètes.

❌ Mauvais exemple

Dépendance directe à une implémentation :

class MySQLDatabase {
    public void sauvegarderCommande(String commande) {
        System.out.println("Commande enregistrée en MySQL");
    }
}

class ServiceCommande {
    private MySQLDatabase db = new MySQLDatabase();
    public void traiterCommande(String commande) {
        db.sauvegarderCommande(commande);
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Bon exemple

Utiliser une interface pour découpler :

interface BaseDeDonnees {
    void sauvegarderCommande(String commande);
}

class MySQLDatabase implements BaseDeDonnees {
    public void sauvegarderCommande(String commande) {
        System.out.println("Commande enregistrée en MySQL");
    }
}

class ServiceCommande {
    private BaseDeDonnees db;
    public ServiceCommande(BaseDeDonnees db) {
        this.db = db;
    }
    public void traiterCommande(String commande) {
        db.sauvegarderCommande(commande);
    }
}
Enter fullscreen mode Exit fullscreen mode

🎯 Conclusion

Les principes SOLID en Java permettent d’avoir un code modulaire, maintenable et extensible. Respecter ces bonnes pratiques améliore la qualité du code et évite les problèmes à long terme ! 🚀

. . . . . . . . . . . . .