vendredi 22 novembre 2024

SOLID

 ===== S ====

Dans le principe SOLID, le "S" représente le principe de Responsabilité Unique (Single Responsibility Principle). En C#, cela signifie que chaque classe doit avoir une seule raison de changer. Par exemple, une classe qui gère la logique métier et l'affichage devrait être séparée en deux classes distinctes, une pour la logique métier et une autre pour l'affichage. Cela rend le code plus lisible, maintenable et évite les effets secondaires inattendus.

// Classe normale

public class Employee

{

public string Name { get; set; }

public decimal CalculatePay()

{

// Logique de calcul de la paie

return 0;

}

public void Save()

{

// Logique de sauvegarde dans la base de données

}

}

// Après l'application du principe de

//Responsabilité Unique

public class Employee

{

public string Name { get; set; }

public decimal CalculatePay()

{

// Logique de calcul de la paie

return 0;

}

}

public class EmployeeRepository

{

public void Save(Employee employee)

{

// Logique de sauvegarde dans la base de données

}

}

Dans cet exemple, la classe Employee a été séparée en deux classes distinctes. Une classe s'occupe uniquement de la logique métier relative aux employés, tandis que l'autre classe est responsable de la sauvegarde des employés dans la base de données. Cela respecte le principe de Responsabilité Unique, améliorant ainsi la maintenabilité et la lisibilité du code.

===== O =====

Le "O" dans SOLID représente le principe d'Ouverture/Fermeture (Open/Closed Principle). Ce principe stipule qu'une classe doit être ouverte à l'extension mais fermée à la modification. En d'autres termes, on devrait pouvoir étendre le comportement d'une classe sans la modifier.

En C#, cela peut être mis en œuvre à l'aide de l'héritage et des interfaces.

// Classe de base

public abstract class Shape

{

public abstract double Area();

}

// Sous-classes étendant la classe de base

public class Circle : Shape

{

public double Radius { get; set; }

public override double Area()

{

return Math.PI * Radius * Radius;

}

}

public class Rectangle : Shape

{

public double Width { get; set; }

public double Height { get; set; }

public override double Area()

{

return Width * Height;

}

}

// Exemple d'utilisation

public class AreaCalculator

{

public double TotalArea(Shape[] shapes)

{

double total = 0;

foreach (var shape in shapes)

{

total += shape.Area();

}

return total;

}

}

Dans cet exemple, la classe Shape est ouverte à l'extension car de nouvelles formes peuvent être ajoutées en créant de nouvelles sous-classes de Shape (par exemple, Triangle, Square) sans modifier la classe AreaCalculator. Ainsi, la classe Shape respecte le principe d'Ouverture/Fermeture.

==== L ====

Le "L" dans SOLID représente le principe du Remplacement de Liskov (Liskov Substitution Principle). Ce principe stipule que les objets d'une classe de base doivent être remplaçables par des objets de ses classes dérivées sans affecter le comportement correct du programme.

public class Rectangle

{

public virtual int Width { get; set; }

public virtual int Height { get; set; }

public int GetArea()

{

return Width * Height;

}

}

public class Square : Rectangle

{

public override int Width

{

set { base.Width = base.Height = value; }

}

public override int Height

{

set { base.Width = base.Height = value; }

}

}

```

Dans cet exemple, la classe Square hérite de la classe Rectangle, mais les propriétés Width et Height sont modifiées pour respecter les caractéristiques d'un carré. En utilisant le principe de substitution de Liskov, un objet de type Rectangle peut être remplacé par un objet de type Square sans altérer le comportement attendu de la classe de base.

==== I ====

Le "I" dans SOLID fait référence au principe d'Interface Segregation Principle (Principe de Ségrégation des Interfaces). Ce principe stipule qu'il est préférable d'avoir de nombreuses interfaces spécifiques plutôt qu'une seule interface générale.

// Interface spécifique pour les opérations de lecture

public interface IReadable

{

void Read();

}

// Interface spécifique pour les opérations d'écriture

public interface IWritable

{

void Write();

}

// Classe utilisant l'interface IReadable

public class FileReader : IReadable

{

public void Read()

{

// Logique de lecture depuis un fichier

}

}

// Classe utilisant l'interface IWritable

public class ConsoleWriter : IWritable

{

public void Write()

{

// Logique d'écriture sur la console

}

}

Dans cet exemple, au lieu d'avoir une interface unique comprenant à la fois la lecture et l'écriture, nous avons des interfaces distinctes pour chaque type d'opération. Cela permet aux classes de mettre en œuvre uniquement les interfaces dont elles ont besoin, respectant ainsi le principe de Ségrégation des Interfaces.

==== D ====

Le “D” dans SOLID fait référence au principe d'Inversion des Dépendances (Dependency Inversion Principle). Ce principe stipule que les modules de haut niveau ne devraient pas dépendre des modules de bas niveau. Au lieu de cela, les deux devraient dépendre de l'abstraction. En outre, les détails doivent dépendre des abstractions, et non l'inverse.

// Interface

public interface ILogger

{

void LogMessage(string message);

}

// Classe de haut niveau dépendant de l'abstraction ILogger

public class ErrorLogger

{

private readonly ILogger _logger;

public ErrorLogger(ILogger logger)

{

_logger = logger;

}

public void LogError(string errorMessage)

{

_logger.LogMessage("Error: " + errorMessage);

}

}

// Classes de bas niveau implémentant l'interface ILogger

public class ConsoleLogger : ILogger

{

public void LogMessage(string message)

{

Console.WriteLine("Logging to console: " + message);

}

}

public class FileLogger : ILogger

{

public void LogMessage(string message)

{

// Log to file implementation

}

}

```

Dans cet exemple, la classe ErrorLogger dépend de l'abstraction ILogger plutôt que de dépendre directement des implémentations concrètes. Cela permet une plus grande flexibilité, car différentes implémentations de ILogger peuvent être utilisées sans modifier la classe ErrorLogger, respectant ainsi le principe d'Inversion des Dépendances.

Aucun commentaire:

Enregistrer un commentaire