một sublcass không nên thay đổi hành vi của cha mẹ?
Đó là cách hiểu sai về LSP. Một lớp con có thể thay đổi hành vi của cha mẹ, miễn là nó vẫn đúng với kiểu cha mẹ.
Có một lời giải thích dài trên Wikipedia , cho thấy những điều sẽ vi phạm LSP:
... có một số điều kiện hành vi mà kiểu phụ phải đáp ứng. Đây là những chi tiết trong một thuật ngữ giống như thiết kế theo phương pháp hợp đồng, dẫn đến một số hạn chế về cách hợp đồng có thể tương tác với kế thừa:
- Điều kiện tiên quyết không thể được tăng cường trong một kiểu con.
- Postconditions không thể được làm yếu trong một kiểu con.
- Bất biến của siêu kiểu phải được bảo toàn trong một kiểu con.
- Ràng buộc lịch sử ("quy tắc lịch sử"). Các đối tượng được coi là có thể sửa đổi chỉ thông qua các phương thức của chúng (đóng gói). Vì các kiểu con có thể giới thiệu các phương thức không có trong siêu kiểu, nên việc giới thiệu các phương thức này có thể cho phép thay đổi trạng thái trong kiểu con không được phép trong siêu kiểu. Các ràng buộc lịch sử cấm điều này. Đó là yếu tố tiểu thuyết được giới thiệu bởi Liskov và Wing. Một hành vi vi phạm ràng buộc này có thể được minh họa bằng cách định nghĩa MutablePoint là một kiểu con của ImmutablePoint. Đây là vi phạm ràng buộc lịch sử, bởi vì trong lịch sử của Điểm bất biến, trạng thái luôn giống nhau sau khi tạo, do đó, nó không thể bao gồm lịch sử của MutablePoint nói chung. Tuy nhiên, các trường được thêm vào kiểu con có thể được sửa đổi một cách an toàn vì chúng không thể quan sát được thông qua các phương thức siêu kiểu.
Cá nhân, tôi thấy dễ dàng hơn để nhớ điều này: Nếu tôi đang xem một tham số trong một phương thức có loại A, liệu ai đó có vượt qua một kiểu con B có gây cho tôi bất ngờ không? Nếu họ sau đó sẽ vi phạm LSP.
Là ném một ngoại lệ là một bất ngờ? Không hẳn vậy. Đó là điều có thể xảy ra bất cứ lúc nào, cho dù tôi đang gọi phương thức Ship trên OrderState hay Granted hoặc Shipped. Vì vậy, tôi phải tính đến nó và nó không thực sự vi phạm LSP.
Điều đó nói rằng , tôi nghĩ có nhiều cách tốt hơn để xử lý tình huống này. Nếu tôi viết điều này bằng C #, tôi sẽ sử dụng các giao diện và kiểm tra việc thực hiện giao diện trước khi gọi phương thức. Ví dụ: nếu OrderState hiện tại không triển khai IShippable, đừng gọi phương thức Ship trên đó.
Nhưng sau đó tôi cũng sẽ không sử dụng mô hình Bang cho tình huống cụ thể này. Mẫu Trạng thái phù hợp hơn nhiều với trạng thái của ứng dụng so với trạng thái của một đối tượng miền như thế này.
Vì vậy, một cách ngắn gọn, đây là một ví dụ kém về Mô hình Nhà nước và không phải là một cách đặc biệt tốt để xử lý trạng thái của một đơn đặt hàng. Nhưng nó được cho là không vi phạm LSP. Và mô hình Nhà nước, tự bản thân nó, chắc chắn là không.