DEV Community

Muhammad Salem
Muhammad Salem

Posted on

1

Understand the Liskov substitution principle using a simple example.

Imagine you're building a delivery system.
Consider an entity class Vehicle and its subclass Car.

public class Vehicle
{
    public virtual void StartEngine()
    {
        // General engine start logic
    }

    public virtual void LoadCargo(int weight)
    {
        // General cargo loading logic
    }
}

public class Car : Vehicle
{
    public override void StartEngine()
    {
        // Car-specific engine start logic
    }

    public override void LoadCargo(int weight)
    {
        if (weight > 500)
        {
            throw new InvalidOperationException("Cars cannot carry more than 500kg");
        }
        // Car-specific cargo loading logic
    }
}
Enter fullscreen mode Exit fullscreen mode

The code violates the Liskov Substitution Principle (LSP) because of the LoadCargo method in the Car class. Here's why:

  1. Base Class Contract: The base class Vehicle defines a LoadCargo(int weight) method with seemingly generic cargo loading logic. This implies any Vehicle can handle loading cargo of any weight.

  2. Derived Class Restriction: The derived class Car overrides LoadCargo and introduces a weight limit of 500kg. This contradicts the base class contract by throwing an exception for weights exceeding the limit.

  3. Substitutability Issue: If you use a Car object anywhere that expects a Vehicle for cargo loading, you might encounter unexpected behavior (the exception) when the weight exceeds 500kg. This breaks the principle of seamless substitution.

How to Fix the Violation:

Solution : Refine Base Class Contract (Weight Limit Property):

public class Vehicle
{
    public virtual int MaxWeightLimit { get { return int.MaxValue; } } // Default unlimited weight

    public virtual void StartEngine()
    {
        // General engine start logic
    }

    public virtual void LoadCargo(int weight)
    {
        if (weight > MaxWeightLimit)
        {
            throw new InvalidOperationException("Vehicle cannot carry more than its weight limit");
        }
        // General cargo loading logic
    }
}

public class Car : Vehicle
{
    public override int MaxWeightLimit { get { return 500; } }

    public override void StartEngine()
    {
        // Car-specific engine start logic
    }

    public override void LoadCargo(int weight)
    {
        // Car-specific cargo loading logic (can be empty if no specific logic needed)
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • We introduce a MaxWeightLimit property in the base class Vehicle with a default value of int.MaxValue (effectively unlimited).
  • The base class LoadCargo method now checks against MaxWeightLimit.
  • The Car class overrides MaxWeightLimit to set its specific limit of 500kg.
  • This way, both Vehicle and Car consistently handle weight limits through the base class contract, adhering to LSP.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay