Tôi đang ở trong một tình huống rất giống với những gì Steve McConnell's trong Hoàn thành mã đã đề cập. Chỉ có vấn đề của tôi là dựa trên Xe cộ và Trike xảy ra là do luật pháp rơi vào hạng mục Ô tô. Ô tô có bốn bánh cho đến bây giờ. Bất kỳ cách nào tên miền của tôi là không cần thiết phức tạp vì vậy nó rất dễ dàng để dính với mèo ví dụ dưới đây.Làm cách nào để tránh vi phạm Nguyên tắc Thay thế Liskov (LSP)?
Hãy nghi ngờ của các lớp học đó ghi đè lên một thói quen và không làm gì cả bên trong thói quen bắt nguồn này thường chỉ ra một lỗi trong thiết kế của các lớp cơ sở. Ví dụ, giả sử bạn có một lớp Cat và Scratch() thường xuyên và giả sử rằng cuối cùng bạn phát hiện ra rằng một số mèo đã bị khai thác và không thể làm xước. Bạn có thể bị cám dỗ để tạo một lớp học bắt nguồn từ Mèo có tên ScratchlessCat và ghi đè lên thủ tục Scratch() để không làm gì cả. Cách tiếp cận này trình bày một số vấn đề:
Vi phạm sự trừu tượng (giao diện hợp đồng) được trình bày trong lớp Cát bằng cách thay đổi ngữ nghĩa giao diện của nó.
Cách tiếp cận này nhanh chóng mất kiểm soát khi bạn mở rộng nó sang các lớp bắt nguồn khác . Điều gì sẽ xảy ra khi bạn tìm thấy một con mèo không có đuôi? Hay con mèo không bắt chuột? Hay một con mèo không uống sữa? Cuối cùng bạn sẽ kết thúc với các lớp học có nguồn gốc như ScratchlessTaillessMicelessMilklessCat.
Theo thời gian, cách tiếp cận này dẫn đến mã gây nhầm lẫn cho duy trì vì các giao diện và hành vi của lớp tổ tiên ngụ ý rất ít hoặc không có gì về hành vi của hậu duệ của chúng.
Nơi khắc phục vấn đề này không nằm trong lớp cơ sở, nhưng trong lớp học ban đầu là Cat. Tạo một lớp Claws và chứa nó trong lớp học Cats. Vấn đề gốc là giả định rằng tất cả các con mèo đầu, để khắc phục vấn đề đó tại nguồn, thay vì chỉ băng bó nó tại đích.
Theo văn bản từ cuốn sách tuyệt vời của ông ở trên. Sau đây là xấu
tầng lớp phụ huynh không phải là trừu tượng
public abstract class Cat {
public void scratch() {
System.out.println("I can scratch");
}
}
nguồn gốc lớp
public class ScratchlessCat extends Cat {
@Override
public void scratch() {
// do nothing
}
}
Giờ đây, ông gợi ý tạo ra một lớp Claws
, nhưng tôi không hiểu làm thế nào có thể Tôi sử dụng lớp này để tránh sự cần thiết cho ScratchlessCat#Scratch
.
Ví dụ về mèo là minh họa tốt về LSP. Trong việc tìm hiểu về LSP, tôi đã ngạc nhiên trước bao nhiêu ví dụ nghèo nàn và có bao nhiêu sự hiểu lầm trên SO và các trang web khác. – SteveT