Principes SOLID en Java : théorie et pratique pour les développeurs

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Principes SOLID en Java : de la théorie au code propre



Tout développeur Java rencontre tôt ou tard le problème du code « sale » : des classes qui font tout à la fois, des dépendances rigides et une impossibilité d'extension sans casser la logique existante. C'est là que les principes SOLID viennent à la rescousse — cinq règles fondamentales de conception orientée objet formulées par Robert Martin (Oncle Bob). Dans cet article, nous analyserons chaque principe en pratique avec des exemples en Java, pour que votre code devienne flexible, testable et facile à maintenir.



1. Single Responsibility Principle (SRP) — principe de responsabilité unique



Essence : « Une classe ne doit avoir qu'une seule raison de changer ». Autrement dit, une classe doit être responsable d'une tâche clairement définie.



Violation du SRP

Considérons la classe OrderService, qui s'occupe simultanément du calcul du prix, de la sauvegarde en base de données et de l'envoi d'email :



public class OrderService {    public void processOrder(Order order) {        // 1. Calcul du coût        double total = order.getItems().stream()                .mapToDouble(Item::getPrice)                .sum();

// 2. Sauvegarde en BDD Database.save(order);

// 3. Envoi de notification EmailService.send("Commande confirmée pour un montant de : " + total); }}


Problème : Modifier la logique d'envoi d'emails ou la méthode de sauvegarde obligerait à changer OrderService. Cela viole le SRP.



Refactorisation selon le SRP

Nous séparons les responsabilités en trois classes distinctes :



public class PriceCalculator {    public double calculateTotal(Order order) {        return order.getItems().stream()                .mapToDouble(Item::getPrice)                .sum();    }}

public class OrderRepository { public void save(Order order) { Database.save(order); }}

public class NotificationService { public void sendConfirmation(Order order) { EmailService.send("Commande confirmée pour un montant de : " + order.getTotal()); }}

// Code clientpublic class OrderProcessor { private PriceCalculator calculator; private OrderRepository repository; private NotificationService notifier;

public void processOrder(Order order) { double total = calculator.calculateTotal(order); order.setTotal(total); repository.save(order); notifier.sendConfirmation(order); }}


Résultat : Chaque classe a une seule raison de changer. Le code devient modulaire et testable.



2. Open-Closed Principle (OCP) — principe d'ouverture/fermeture



Essence : « Les entités logicielles doivent être ouvertes à l'extension, mais fermées à la modification ». Les nouvelles fonctionnalités sont ajoutées par extension, et non en modifiant le code existant.



Violation de l'OCP

Imaginons un système de remises où chaque nouveau type de remise nécessite de modifier la méthode applyDiscount :



public class DiscountService {    public double applyDiscount(String type, double price) {        if (type.equals("SUMMER")) {            return price * 0.9;        } else if (type.equals("VIP")) {            return price * 0.8;        }        // Ajout d'un nouveau type → modification de la classe        return price;    }}


Solution via le polymorphisme

Utilisons une interface et différentes implémentations :



public interface Discount {    double apply(double price);}

public class SummerDiscount implements Discount { @Override public double apply(double price) { return price * 0.9; }}

public class VipDiscount implements Discount { @Override public double apply(double price) { return price * 0.8; }}

// Nouveau type — simplement une nouvelle classe

Blogs

Book Recommendations