Introduction : Pourquoi SOLID est la base d'un code C# de qualité
Le développement en C# dans l'écosystème .NET nécessite non seulement la connaissance de la syntaxe, mais aussi la capacité de concevoir des applications flexibles, maintenables et testables. SOLID est l'acronyme de cinq principes fondamentaux de conception orientée objet, formulés par Robert Martin. Ils aident les développeurs à éviter les dépendances "rigides", la duplication de code et les problèmes lors de la mise à l'échelle.
Dans cet article, nous analyserons chacun des cinq principes SOLID appliqués à C# : de la théorie aux exemples de code concrets. Vous apprendrez comment le refactoring avec SOLID rend votre code plus propre et la maintenance des projets plus simple.
1. Single Responsibility Principle (SRP) — Principe de responsabilité unique
Théorie
Une classe ne doit avoir qu'une seule raison de changer. Autrement dit, chaque classe est responsable d'exactement une fonctionnalité ou une logique métier. Si une classe fait trop de choses, elle devient difficile à tester, à modifier et à réutiliser.
Pratique : violation du SRP
public class OrderProcessor{ public void ProcessOrder(Order order) { // 1. Validation de la commande if (order.Total <= 0) throw new Exception("Invalid order"); // 2. Sauvegarde dans la base de données using var db = new AppDbContext(); db.Orders.Add(order); db.SaveChanges(); // 3. Envoi d'une notification par email SmtpClient client = new SmtpClient(); client.Send("admin@shop.com", order.CustomerEmail, "Order confirmed", "Thank you!"); }}Ici, OrderProcessor viole le SRP : il est responsable de la validation, du travail avec la base de données et de l'envoi d'email. Une modification de la logique d'envoi des notifications nécessitera de modifier cette même classe.
Refactoring avec SRP
public class OrderValidator{ public bool Validate(Order order) => order.Total > 0;}
public class OrderRepository{ public void Save(Order order) { using var db = new AppDbContext(); db.Orders.Add(order); db.SaveChanges(); }}
public class EmailService{ public void SendConfirmation(string email) { SmtpClient client = new SmtpClient(); client.Send("admin@shop.com", email, "Order confirmed", "Thank you!"); }}
public class OrderProcessor{ private readonly OrderValidator _validator; private readonly OrderRepository _repository; private readonly EmailService _emailService;
public OrderProcessor(OrderValidator validator, OrderRepository repository, EmailService emailService) { _validator = validator; _repository = repository; _emailService = emailService; }
public void ProcessOrder(Order order) { if (!_validator.Validate(order)) throw new Exception("Invalid order"); _repository.Save(order); _emailService.SendConfirmation(order.CustomerEmail); }}Maintenant, chaque classe a un seul domaine de responsabilité. Cela simplifie les tests et la modification.
2. Open/Closed Principle (OCP) — Principe d'ouverture/fermeture
Théorie
Les entités logicielles (classes, modules, fonctions) doivent être ouvertes à l'extension, mais fermées à la modification. C'est-à-dire que vous devez pouvoir ajouter de nouvelles fonctionnalités sans modifier le code existant.
Pratique : violation du OCP
public class ShapeDrawer{ public void DrawShape(object shape) { if (shape is Circle circle) Console.WriteLine($"Drawing circle with radius {circle.Radius}"); else if (shape is Rectangle rect) Console.WriteLine($"Drawing rectangle {rect.Width}x{rect.Height}"); // Lors de l'ajout d'un nouveau type de forme — il faut modifier cette méthode ! }}Refactoring avec OCP via abstraction
public abstract c