principes SOLID

Écrit Par :

Catégorie:

Développement avancé

Date :

Partager :

Cours complet – Principes SOLID en .NET

1. Introduction aux principes SOLID

Les principes SOLID sont les fondations du développement orienté objet moderne. Ils visent à améliorer la qualité du code, à le rendre plus lisible, modulaire, et facilement testable. Voici un résumé des 5 principes :

LettreNomDescription
SSingle Responsibility PrincipleUne classe doit avoir une seule responsabilité
OOpen/Closed PrincipleOuvert à l’extension, fermé à la modification
LLiskov Substitution PrincipleUne sous-classe doit pouvoir remplacer sa classe mère
IInterface Segregation PrinciplePréférer plusieurs interfaces spécifiques à une interface générale
DDependency Inversion PrincipleDépendre d’abstractions, pas de classes concrètes

2. Les principes SOLID expliqués avec cohérence

2.1 – SRP : Une seule responsabilité

Un service de commande ne devrait pas gérer l’envoi d’email, ni la génération de factures. Chaque classe a une seule tâche.

Mauvais exemple

public class CommandeService {
    public void CréerCommande() {}
    public void EnvoyerConfirmationEmail() {}
    public void GénérerFacture() {}
}

Bon exemple

public class CommandeService {
    public void CréerCommande() {}
}

public class EmailService {
    public void EnvoyerConfirmationEmail() {}
}

public class FactureService {
    public void GénérerFacture() {}
}

2.2 – OCP : Ouvert à l’extension, fermé à la modification

Si on veut ajouter un nouveau type de livraison, on ne devrait pas modifier le service existant.

public class CalculateurLivraison {
    public double CalculerFrais(string type) {
        if (type == "standard") return 5;
        if (type == "express") return 10;
        return 0;
    }
}
public interface ICalculateurFrais {
    double Calculer();
}

public class LivraisonStandard : ICalculateurFrais {
    public double Calculer() => 5;
}

public class LivraisonExpress : ICalculateurFrais {
    public double Calculer() => 10;
}

2.3 – LSP : Substitution cohérente

Une classe enfant ne doit pas casser les attentes de la classe parent.

public class MoyennePaiement {
    public virtual void EffectuerPaiement() {}
}

public class PaiementTest : MoyennePaiement {
    public override void EffectuerPaiement() {
        throw new NotSupportedException();
    }
}
public interface IPaiement {
    void EffectuerPaiement();
}

public class PaiementCarte : IPaiement {
    public void EffectuerPaiement() {}
}

public class PaiementVirement : IPaiement {
    public void EffectuerPaiement() {}
}

2.4 – ISP : Interfaces spécifiques

Les interfaces doivent être courtes et ciblées.

public interface IServiceClient {
    void Commander();
    void Payer();
    void NotifierClient();
}
public interface ICommandable {
    void Commander();
}

public interface IPayable {
    void Payer();
}

public interface INotifiable {
    void NotifierClient();
}

2.5 – DIP : Dépendre d’abstractions

Une classe ne doit pas créer ses dépendances mais les recevoir de l’extérieur.

public class NotificationService {
    private EmailService email = new EmailService();
}
public class NotificationService {
    private readonly IEmailService _emailService;

    public NotificationService(IEmailService emailService) {
        _emailService = emailService;
    }
}

3. Énoncé de l’exercice

Vous avez un service qui gère la commande, l’envoi d’email, le stockage et la génération de facture. Ce service viole plusieurs principes SOLID. Refactorez-le en respectant chaque principe un par un.

public class CommandeService {
    public void CréerCommande() {}
    public void EnvoyerEmail() {}
    public void SauvegarderCommande() {}
    public void GénérerFacture() {}
}

4. Correction étape par étape

Étape 1 – SRP

On sépare chaque action dans sa propre classe.

public class CommandeService { public void CréerCommande() {} }
public class EmailService { public void EnvoyerEmail() {} }
public class FactureService { public void GénérerFacture() {} }
public class CommandeRepository { public void SauvegarderCommande() {} }

Étape 2 – OCP

On permet l’ajout de nouvelles stratégies de facturation sans modifier le code existant.

public interface IStrategieFacture {
    void Générer();
}

public class FacturePDF : IStrategieFacture {
    public void Générer() {}
}

Étape 3 – LSP

Les classes de notifications respectent l’interface et peuvent être substituées.

public interface INotification {
    void Envoyer();
}

public class EmailNotification : INotification {
    public void Envoyer() {}
}

Étape 4 – ISP

On découpe les interfaces pour que chaque classe n’implémente que ce dont elle a besoin.

public interface ICommandeService { void CréerCommande(); }
public interface IFacturation { void GénérerFacture(); }

Étape 5 – DIP

On injecte les dépendances via le constructeur plutôt que de les instancier directement.

public class GestionCommande {
    private readonly ICommandeService _commande;
    public GestionCommande(ICommandeService commande) {
        _commande = commande;
    }
}

5. Conclusion

Les principes SOLID vous aident à concevoir des architectures logicielles évolutives et robustes. En appliquant ces principes au quotidien, vous améliorez la qualité de vos projets, la collaboration en équipe et la maintenabilité de votre code.