Interview frequency: …
Short answer
LSP says objects of a derived class must be usable in place of objects of the base class without changing program correctness or behavior. A child must not strengthen preconditions or weaken postconditions.
Explanation
The classic example is a Square class inheriting from Rectangle. If you change setWidth() on the square, you must also change its height to keep the sides equal. But code using a Rectangle expects changing width not to affect height. Replacing the rectangle with a square breaks the calculation logic. Liskov's strict rules are: (1) a child cannot strengthen preconditions; (2) it cannot weaken postconditions; (3) class invariants must be preserved; and (4) it must not throw unexpected exceptions compared with the parent.
Code example
class Rectangle {
constructor(protected w: number, protected h: number) {}
setWidth(val: number) { this.w = val; }
setHeight(val: number) { this.h = val; }
getArea(): number { return this.w * this.h; }
}
// LSP violation: the square secretly changes height behavior when width changes!Common mistakes
- Inheriting from a class and throwing NotImplementedException in some methods, directly violating LSP and breaking callers' expectations.