SOLID Principal
September 8, 2025
L – Liskov Substitution Principle (Nguyên tắc thay thế Liskov)
Một class con có thể thay thế class cha mà không làm thay đổi tính đúng đắn của chương trình.
- Nếu B kế thừa A, thì các đối tượng B có thể sử dụng thay cho A mà không gặp lỗi.
Wrong
class Bird {
public function fly() {}
}
class Ostrich extends Bird {
public function fly() {
throw new Exception("Đà điểu không biết bay!");
}
}
Right
interface Bird { public function eat(); }
interface Flyable { public function fly(); }
class Sparrow implements Bird, Flyable {
public function eat() {}
public function fly() {}
}
class Ostrich implements Bird {
public function eat() {}
}
- Trọng tâm: Tính thay thế hợp lệ trong kế thừa.
- Ý nghĩa: Nếu B kế thừa A, thì mọi nơi dùng A đều có thể thay bằng B mà không làm thay đổi logic chương trình.
- Khi vi phạm: Thường xảy ra khi class con không thực sự là một loại của class cha.
Lợi ích của LSP
- Tính thay thế an toàn: Code hoạt động ổn định khi thay BaseClass bằng Subclass.
- Giúp thiết kế abstraction đúng đắn hơn: Buộc dev phải suy nghĩ “liệu quan hệ kế thừa này có thực sự đúng?”
- Dễ mở rộng mà không phá vỡ logic: Có thể thêm nhiều class con mà không làm hỏng phần code đang chạy.
- Giúp tái sử dụng: Khi abstraction đúng, hệ thống dễ tái sử dụng hơn (ví dụ Flyable áp dụng cho Chim, Máy bay, Drone…).
Bất cập của LSP
- Khó xác định “hợp lệ”: Trong thực tế, không phải lúc nào cũng rõ ràng subclass có thay thế hợp lệ không.
- Ví dụ: Square kế thừa Rectangle nghe hợp lý về hình học, nhưng trong code lại vi phạm (khi thay đổi chiều dài/rộng độc lập).
- Thiết kế abstraction quá phức tạp: Để đảm bảo tuân thủ LSP, đôi khi ta phải tạo thêm nhiều interface/abstraction phụ, khiến hệ thống “rườm rà”.
- Tốn effort ban đầu: Cần nhiều phân tích trước khi viết code để tránh quan hệ kế thừa sai.
- Không phải lúc nào cũng khả thi: Với dự án nhỏ, việc “bẻ” abstraction để đúng LSP có thể làm chậm tiến độ.

