LSP (chữ "L" trong SOLID, Barbara Liskov 1987): subtype phải thay thế được supertype mà không phá hành vi chương trình. Code chạy với Animal phải chạy đúng khi đưa Dog vào — không bug bất ngờ.
Ví dụ kinh điển vi phạm — Square is-a Rectangle:
class Rectangle {
public void setWidth(int w) { this.width = w; }
public void setHeight(int h) { this.height = h; }
public int area() { return width * height; }
}
class Square extends Rectangle {
@Override public void setWidth(int w) { this.width = w; this.height = w; }
@Override public void setHeight(int h) { this.width = h; this.height = h; }
}
void resize(Rectangle r) {
r.setWidth(5); r.setHeight(10);
assert r.area() == 50; // ❌ FAIL nếu r là Square (area = 100)
}Toán học: hình vuông là hình chữ nhật. Hành vi: không tương thích. Hierarchy sai từ thiết kế.
Ví dụ khác — Penguin extends Bird nhưng override fly() throw UnsupportedOperationException → caller Bird b = ...; b.fly(); crash khi b là Penguin.
Giải pháp: tách interface theo năng lực — Flyable, Swimmable. Liên quan chặt với ISP (Interface Segregation).
Cách phát hiện vi phạm:
- instanceof check rồi xử lý đặc biệt.
- Override method bằng throw UnsupportedOperationException.
- Override để no-op khi parent có hành vi cụ thể.
LSP không kiểm được bằng compiler — phải tự đảm bảo qua thiết kế + test polymorphism.
LSP (the "L" in SOLID, Barbara Liskov 1987): a subtype must be substitutable for its supertype without breaking program behaviour. Code written for Animal must still work correctly when given a Dog — no surprises.
Classic violation — Square is-a Rectangle:
class Rectangle {
public void setWidth(int w) { this.width = w; }
public void setHeight(int h) { this.height = h; }
public int area() { return width * height; }
}
class Square extends Rectangle {
@Override public void setWidth(int w) { this.width = w; this.height = w; }
@Override public void setHeight(int h) { this.width = h; this.height = h; }
}
void resize(Rectangle r) {
r.setWidth(5); r.setHeight(10);
assert r.area() == 50; // ❌ FAILS if r is a Square (area = 100)
}Mathematically a square is a rectangle. Behaviourally they are not compatible. The hierarchy is wrong by design.
Another — Penguin extends Bird overrides fly() with throw UnsupportedOperationException → a caller Bird b = ...; b.fly(); crashes when b is a Penguin.
Solution: split interfaces by capability — Flyable, Swimmable. Closely related to ISP (Interface Segregation).
How to spot violations:
- instanceof checks followed by special handling.
- Overriding methods with throw UnsupportedOperationException.
- Overriding to no-op when the parent has real behaviour.
LSP cannot be checked by the compiler — enforce it through design + thorough polymorphic tests.