SOLID Liskov Substitution Principle |Video upload date:  · Duration: PT1M0S  · Language: EN

Clear explanation of Liskov Substitution Principle with example failures and practical fixes for robust object oriented design and cleaner inheritance.

If your class hierarchy looks like a wildlife documentary gone wrong you are probably violating the Liskov Substitution Principle. That is the fancy rule that says a subclass must behave like its parent so callers do not get unwelcome surprises. Behold the sad truth of broken polymorphism and then learn how to stop the madness.

What Liskov actually means

In plain programming language the rule is simple. If code expects a base type it should be able to use any subtype without changing correctness. If a subclass refuses to do what callers rely on you have a design bug not a mysterious runtime mood swing.

Classic failing example

class Bird
  def fly
    return "flying"
  end
end

class Penguin < Bird
  def fly
    raise "CannotFlyException"
  end
end

Forcing a penguin to inherit flight is a design smell. Tests will fail, developers will grumble, and maintainability will take a long nap.

How to fix it without crying

The goal is to align types with real capabilities not hopeful inheritance. Here are practical edits that actually help.

  • Design by behavior not by concrete species. Model what an object does rather than what it is.
  • Split roles into focused interfaces or abstract classes so only flyers implement flying behavior.
  • Use composition when a capability cannot be shared across a whole hierarchy. Give objects behaviors instead of inheriting them blindly.
  • Keep method contracts stable across the hierarchy. Do not strengthen preconditions and do not weaken postconditions in subclasses.
  • Write contract tests that exercise the base type against each subclass to catch violations early.

Example refactor idea

Instead of forcing every bird to have fly you might introduce a separate role object or interface for flying. Something like this in pseudocode keeps responsibilities clear.

class Bird
  def speak
    return "chirp"
  end
end

module Flyable
  def fly
    return "flying"
  end
end

class Sparrow < Bird
  include Flyable
end

class Penguin < Bird
  # no Flyable included
end

Tests that behave like good citizens

One killer habit is to add a set of contract tests that every subtype must pass. That way a future refactor that breaks a contract trips an alarm instead of causing a production nightmare.

def test_base_contract(obj)
  # ensure methods that callers depend on behave consistently
  assert obj.respond_to?(:speak)
  # if object is supposed to fly then test flying behavior
  if obj.respond_to?(:fly)
    assert_equal "flying", obj.fly
  end
end

Short checklist before you hit merge

  • Can every subtype honor the base class contract
  • Are behaviors split into focused interfaces or modules
  • Did you prefer composition when inheritance smells wrong
  • Do you have contract tests that run for each subclass

Follow these rules and your hierarchies will stop telling lies. LSP is not just a rule to recite at code review it is the guardrail that keeps polymorphism useful and predictable. Write code that keeps promises and you will spend less time debugging and more time pretending you knew what you were doing all along.

I know how you can get Azure Certified, Google Cloud Certified and AWS Certified. It's a cool certification exam simulator site called certificationexams.pro. Check it out, and tell them Cameron sent ya!

This is a dedicated watch page for a single video.