Liskov Substitution Principle
- Principle:
Every subclass or derived class should be substitutable for their base or parent class.
Example: Here we have a Bird base class and two derived classes FlyingBird and Penguin -
public class Bird
{
public virtual void Fly()
{
Console.WriteLine("I am flying");
}
}
public class FlyingBird : Bird
{
}
public class Penguin : Bird
{
public override void Fly()
{
throw new InvalidOperationException("Penguins can't fly");
}
}
In this example, a Penguin cannot fly. This is in violation of the Liskov Substitution Principle because if we used a function like this -
public void MakeBirdFly(Bird bird)
{
bird.Fly();
}
It would work well with a FlyingBird object, but it would throw an exception with a Penguin object -
Bird bird1 = new FlyingBird();
MakeBirdFly(bird1); // works fine
Bird bird2 = new Penguin();
MakeBirdFly(bird2); // throws exception
This breaks the principle because a Penguin object cannot properly substitute for a Bird object.
The principle suggests that a better design would be to move the Fly method into only those classes that can actually fly -
// Base class
public class Bird
{
}
// Flying bird class with Fly method
public class FlyingBird : Bird
{
public virtual void Fly()
{
Console.WriteLine("I am flying");
}
}
// Penguin class without Fly method
public class Penguin : Bird
{
}
Last modified: 23 September 2024