CMD Guide
HomeOO & Low-Level DesignSOLID Principles

Break The Hierarchy for Adhering to LSP

What LSP actually requires — and why renaming a method doesn't satisfy it

The Liskov Substitution Principle: objects of a subtype must be usable anywhere the base type is expected, without breaking the program's correctness. A subclass may not weaken a guarantee the base type makes. The earlier page "fixed" an LSP violation by renaming ElectricCar.refuel() to recharge() and declared LSP satisfied — but renaming changes nothing: any code holding a Car and calling refuel() still breaks for an electric car. LSP is about behavioural substitutability, not method names.

The canonical violation: Square is-a Rectangle

class Rectangle {
    protected int w, h;
    void setWidth(int w)  { this.w = w; }
    void setHeight(int h) { this.h = h; }
    int area() { return w * h; }
}
class Square extends Rectangle {            // "a square IS a rectangle" — mathematically yes, behaviourally NO
    void setWidth(int w)  { this.w = w; this.h = w; }   // forced to keep sides equal
    void setHeight(int h) { this.w = h; this.h = h; }
}

// client code written against Rectangle:
void resizeAndCheck(Rectangle r) {
    r.setWidth(5);
    r.setHeight(4);
    assert r.area() == 20;     // holds for Rectangle; FAILS for Square (area == 16)
}

Passing a Square to resizeAndCheck breaks an assertion that holds for every Rectangle — so Square is not a behavioural subtype. The inheritance is the bug.

The fix: restructure so subtypes keep every base promise

Don't force an "is-a" that violates behaviour. Give them a common abstraction that only promises what both can honour, and drop the false inheritance:

interface Shape { int area(); }                 // the honest common contract

class Rectangle implements Shape {
    private final int w, h;
    Rectangle(int w, int h) { this.w = w; this.h = h; }
    public int area() { return w * h; }
}
class Square implements Shape {
    private final int side;
    Square(int side) { this.side = side; }
    public int area() { return side * side; }
}

Same lesson for the cars: a base Car should only promise what all cars do (e.g. drive()). Refuelling is not universal, so it doesn't belong on Car — put it on a GasolineCar / Refuelable abstraction. Then no caller of Car can invoke something a subtype can't honour.

How to spot an LSP violation before it ships

When inheritance is still right — and when composition wins

Follow-up drills

  1. Penguin / fly. Bird has fly(); Penguin cannot fly. Is the hierarchy wrong or the method wrong? Defend both repairs: (a) remove fly from Bird, introduce Flyable; (b) keep Bird without flight and compose flight capability. Which fits a zoo domain where most birds fly?
  2. instanceof as smell. Client code does if (shape instanceof Square) { ... } else if (shape instanceof Rectangle) { ... }. What does that prove about the abstraction? Refactor so the client only calls area() (or a visitor if you truly need type-specific ops on a closed set).
  3. Numeric recap. Walk setWidth(5); setHeight(4); on Square-as-Rectangle and state the area that fails the assert: 16, not 20.

Takeaways


Re-authored for correctness for this guide (the prior version claimed renaming refuel→recharge satisfied LSP). Per Barbara Liskov's substitution principle & Martin's SOLID. See also: Composition for LSP, Interface Segregation.

🤖 Don't fully get this? Learn it with Claude

Stuck on Break The Hierarchy for Adhering to LSP? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Break The Hierarchy for Adhering to LSP** (OO & Low-Level Design) and want to truly understand it. Explain Break The Hierarchy for Adhering to LSP from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Break The Hierarchy for Adhering to LSP** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Break The Hierarchy for Adhering to LSP** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Break The Hierarchy for Adhering to LSP** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes