Skip to the content.

Liskov Substitution Principle

Anywhere a supertype works, every subtype must work too.

The violation

Making the free sample “a kind of book” because it shares a few fields:

class FreeSampleChapter extends Book {
    @Override
    BigDecimal price() {
        throw new UnsupportedOperationException("samples can't be bought!");
    }
}

Now every piece of code handling books – totals, receipts, recommendations – can blow up at runtime on a subtype it was promised would behave like a Book. Callers start adding instanceof FreeSampleChapter guards, which is the design admitting the inheritance was a lie.

The fix

Subtyping follows behaviour, not field overlap. PrintedBook and Ebook genuinely keep the Purchasable contract, so Till.totalOf works on any mix of them with no guards. FreeSampleChapter simply isn’t Purchasable – the compiler stops it reaching the till, instead of an exception stopping the sale.

Benefits

Example test

TillLspTest