Liskow
🛠️ Pourquoi le LSP est-il important ?
| Avantage | Explication |
|---|---|
| Robustesse | Évite les bugs liés à une mauvaise hiérarchie de classes. |
| Maintenabilité | Facilite la compréhension et l'évolution du code. |
| Réutilisabilité | Permet d'utiliser les sous-classes de manière interchangeable. |
⚡ Note : Respecter le LSP permet d’écrire des hiérarchies sûres et prévisibles.
🪄 Comment appliquer le LSP ?
Pour respecter le LSP, il faut :
- Ne pas renforcer les préconditions dans les sous-classes.
- Ne pas affaiblir les postconditions dans les sous-classes.
- Ne pas changer les invariants de la classe de base.
- Éviter de lever des exceptions inattendues dans les sous-classes.
ℹ️ Astuce : Si une sous-classe ne peut pas respecter toutes les règles de la classe parente, il vaut mieux repenser la hiérarchie ou utiliser la composition.
📩 Exemple en C#
❌ Mauvaise pratique : Violation du LSP
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public int Area => Width * Height;
}
public class Square : Rectangle
{
public override int Width
{
get => base.Width;
set { base.Width = base.Height = value; }
}
public override int Height
{
get => base.Height;
set { base.Width = base.Height = value; }
}
}
// Utilisation
public void TestArea(Rectangle rectangle)
{
rectangle.Width = 5;
rectangle.Height = 4;
Console.WriteLine($"Aire attendue : 20, aire calculée : {rectangle.Area}");
}
// Problème : Si on passe un Square, le résultat sera 16 au lieu de 20 !
ℹ️ Problème : Un
Squaren'est pas substituable à unRectanglecar il modifie le comportement attendu.
✅ Bonne pratique : Respect du LSP
public abstract class Shape
{
public abstract int Area { get; }
}
public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
public override int Area => Width * Height;
}
public class Square : Shape
{
public int Side { get; set; }
public override int Area => Side * Side;
}
// Utilisation
public void PrintArea(Shape shape)
{
Console.WriteLine($"Aire : {shape.Area}");
}
// Rectangle et Square sont interchangeables en tant que Shape.
ℹ️ Avantages :
- Chaque classe a un comportement cohérent et prévisible.
- Le code client (
PrintArea) fonctionne correctement avec n'importe quelle sous-classe deShape.- Pas de surprises lors de l'exécution.
⚡ Problèmes fréquents / Causes probables
| Symptôme | Cause probable | Solution |
|---|---|---|
| Sous-classe change le comportement attendu de la classe parente | Préconditions/postconditions non respectées | Revoir la hiérarchie ou utiliser la composition |
| Bugs subtils lors de l'utilisation polymorphique | Méthodes qui lèvent des exceptions inattendues | Garantir que toutes les méthodes respectent les invariants de la classe de base |
| Difficulté à substituer les objets | Sous-classes trop spécifiques ou couplées | Créer des classes abstraites ou interfaces génériques |
🎯 Conclusion
Le Liskov Substitution Principle garantit que l'héritage est utilisé de manière sûre et prévisible. En respectant ce principe, on évite les bugs subtils et on rend le code plus robuste, maintenable et réutilisable.