• Skip to main content
  • Skip to primary sidebar
  • Skip to footer

Alex Aitken

Technical and Engineering Leadership, Coaching, and Mentorship

L for Liskov Substitution Principle

May 21, 2018 By Alex 1 Comment

Derived classes must be substitutable for their base classes.
Robert C. Martin

Welcome back to the series on SOLID. By now, I’ll assume you’ve read my earlier post on the Open/Closed Principle. This principle is quite an obvious principle. I’m going to use the time-and-time-again Duck example below. Think: If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck. That is unless you break the Liskov Substitution Principle. With this principle, you must be able to substitute any object for its base type. What do I mean? Let’s say you have a duck base class. You can add a Mallard Duck, a Marbled Duck, and a Rubber Duck. But – a rubber duck can’t fly. It’ll break your base class implementation of a Duck. You’ll see more below.

Breaking the principle

So, as I explained above: We’ll start by using a Duck base class. In this base class, we’ll have a method Quack(). We’ll also add a few duck types.

public abstract class Duck
{
    public abstract void Quack();
}

public class MallardDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }
}

public class MarbledDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }
}

public class RubberDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Squeak!");
    }
}

But, you realise that Ducks also Swim, right? I mean they should swim. So far, so good.

public abstract class Duck
{
    public abstract void Quack();
    public abstract void Swim();
}

public class MallardDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }
}

public class MarbledDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }
}

public class RubberDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Squeak!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Floating!");
    }
}

Finally, you realise that Ducks should also fly. Do you know a duck that can’t fly?

public abstract class Duck
{
    public abstract void Quack();
    public abstract void Swim();
    public abstract void Fly();
}

public class MallardDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }

    public override void Fly()
    {
        System.Console.WriteLine("Flying!");
    }
}

public class MarbledDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }

    public override void Fly()
    {
        System.Console.WriteLine("Flying!");
    }
}

public class RubberDuck : Duck
{
    public override void Quack()
    {
        System.Console.WriteLine("Squeak!");
    }

    public override void Swim()
    {
        System.Console.WriteLine("Floating!");
    }

    public override void Fly()
    {
        throw new Exception("Rubber ducks can't fly!");
    }
}

Uh oh! A Rubber Duck can’t fly. Let’s use this principle: Subtypes must be substitutable for their base types. Can we substitute RubberDuck for a Duck? No. Because it’ll throw an exception. We definitely don’t want that. So how do we fix this code? Should we fix it?

Fix using the principle

Well, to be honest, a Rubber Duck shouldn’t be a Duck. Full Stop. If we really wanted to fix this, we can use the next principle to take out the Duck abstraction. We can have an interface for Quack, Swim, and Fly. We won’t have a Duck base class anymore, but we’ll have ducks who can do all three and ducks who can only do two.

public interface IFly
{
    void Fly();
}

public interface ISwim
{
    void Swim();
}

public interface IQuack
{
    void Quack();
}

public class MallardDuck : IFly, ISwim, IQuack
{
    public void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }

    public void Fly()
    {
        System.Console.WriteLine("Flying!");
    }
}

public class MarbledDuck : IFly, ISwim, IQuack
{
    public void Quack()
    {
        System.Console.WriteLine("Quack!");
    }

    public void Swim()
    {
        System.Console.WriteLine("Swimming!");
    }

    public void Fly()
    {
        System.Console.WriteLine("Flying!");
    }
}

public class RubberDuck : ISwim, IQuack
{
    public void Quack()
    {
        System.Console.WriteLine("Squeak!");
    }

    public void Swim()
    {
        System.Console.WriteLine("Floating!");
    }
}

L for Liskov Substitution Principle

I hope this was a little help explaining the principle. Ducks will be ducks, but a rubber duck is not a duck. Remember that you should be able to substitute your subclass for you base class at any point and we should expect it to do what’s expected. If it ends up doing something unexpected, then you’re probably breaking the Liskov substitution principle.

Republished on Medium.

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook

Like this:

Like Loading...

Related

Filed Under: Coding

Alex

Reader Interactions

Trackbacks

  1. SOLID Yazılım Geliştirme Prensipleri Bölüm 2 – Kadir Karagöz Blog says:
    September 22, 2023 at 10:08 pm

    […] https://www.alexaitken.nz/blog/l-for-liskov-substitution-principle/ […]

    Loading...
    Reply

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

About the author

Alex is an AVP of Engineering currently working at Bukalapak. He is a leader in full-stack technologies. Read More…

Pages

  • Speaking Experience
  • About

Social Profiles

  • LinkedIn
  • Medium
  • ADPList

Recent Posts

  • Interviewing as an Engineering Leader
  • Managing Low Performers
  • Getting Docker, React, .NET Core, Postgres, and Nginx Playing Nice
  • What Makes a Good Software Engineering Manager?
  • “Am I There Yet?” Said an Engineer

Archives

  • January 2025
  • August 2024
  • July 2024
  • October 2023
  • August 2023
  • October 2020
  • May 2020
  • February 2020
  • June 2019
  • March 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • January 2018

Categories

  • Coding
  • Essay
  • Leadership
  • Management
  • Roundtable
  • Strategy

Footer

Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy

Copyright © 2025

%d