Aller au contenu principal

Liskow

🛠️ Pourquoi le LSP est-il important ?

AvantageExplication
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 Square n'est pas substituable à un Rectangle car 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 de Shape.
  • Pas de surprises lors de l'exécution.

⚡ Problèmes fréquents / Causes probables

SymptômeCause probableSolution
Sous-classe change le comportement attendu de la classe parentePréconditions/postconditions non respectéesRevoir la hiérarchie ou utiliser la composition
Bugs subtils lors de l'utilisation polymorphiqueMéthodes qui lèvent des exceptions inattenduesGarantir que toutes les méthodes respectent les invariants de la classe de base
Difficulté à substituer les objetsSous-classes trop spécifiques ou coupléesCré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.