Tôi sẽ chọn Java làm ví dụ, hầu hết mọi người đều biết điều đó, mặc dù mọi ngôn ngữ OO khác cũng đang hoạt động.Có phải OOP & hoàn toàn tránh thừa kế thực hiện có thể không?
Java, giống như nhiều ngôn ngữ khác, có kế thừa giao diện và kế thừa thực hiện. Ví dụ. một lớp Java có thể kế thừa từ một phương thức khác và mọi phương thức có thực hiện ở đó (giả sử cha mẹ không trừu tượng) cũng được kế thừa. Điều đó có nghĩa là giao diện được kế thừa và thực hiện cho phương thức này. Tôi có thể ghi đè lên nó, nhưng tôi không phải. Nếu tôi không ghi đè lên nó, tôi đã thừa kế việc thực hiện.
Tuy nhiên, lớp học của tôi cũng có thể "kế thừa" (không phải trong thuật ngữ Java) chỉ là một giao diện, mà không cần triển khai. Trên thực tế các giao diện thực sự được đặt tên theo cách đó trong Java, chúng cung cấp sự thừa kế giao diện, nhưng không thừa hưởng bất kỳ việc triển khai thực hiện nào, vì tất cả các phương thức của một giao diện không thực hiện.
Bây giờ đã có số này article, saying it's better to inherit interfaces than implementations, bạn có thể muốn đọc nó (ít nhất là nửa đầu của trang đầu tiên), nó khá thú vị. Nó tránh các vấn đề như fragile base class problem. Cho đến nay điều này làm cho tất cả rất nhiều ý nghĩa và nhiều điều khác nói trong bài viết làm cho rất nhiều ý nghĩa với tôi.
Điều gì làm phiền tôi về điều này, đó là thừa kế thực hiện nghĩa là sử dụng lại mã tái sử dụng, một trong những thuộc tính quan trọng nhất của ngôn ngữ OO. Bây giờ nếu Java không có các lớp (như James Gosling, bố già của Java đã mong muốn theo bài viết này), nó giải quyết mọi vấn đề về kế thừa thực hiện, nhưng làm thế nào bạn sẽ làm cho việc tái sử dụng mã có thể sau đó?
Ví dụ: nếu tôi có một lớp Xe hơi và Xe hơi có phương pháp di chuyển(), điều này làm cho Xe di chuyển. Bây giờ tôi có thể phân loại xe hơi cho các loại xe khác nhau, đó là tất cả các xe hơi, nhưng tất cả đều là phiên bản chuyên biệt của ô tô. Một số có thể di chuyển theo một cách khác, những cần phải ghi đè lên move() anyway, nhưng hầu hết chỉ đơn giản là giữ di chuyển thừa kế, khi chúng di chuyển giống hệt như cha mẹ trừu tượng. Bây giờ giả sử trong một giây chỉ có các giao diện trong Java, chỉ các giao diện có thể kế thừa từ nhau, một lớp có thể thực hiện các giao diện, nhưng tất cả các lớp luôn là cuối cùng, vì vậy không có lớp nào có thể kế thừa từ bất kỳ lớp nào khác.
Làm thế nào bạn tránh được điều đó khi bạn có một chiếc xe giao diện và hàng trăm lớp học xe hơi, bạn cần phải thực hiện một phương thức move() giống hệt nhau cho mỗi người trong số họ? Khái niệm tái sử dụng mã nào khác hơn là thừa kế thực hiện tồn tại trong thế giới OO?
Một số ngôn ngữ có Mixins. Mixins câu trả lời cho câu hỏi của tôi? Tôi đã đọc về chúng, nhưng tôi không thể tưởng tượng Mixins sẽ làm việc như thế nào trong một thế giới Java và nếu chúng thực sự có thể giải quyết được vấn đề ở đây.
Một ý tưởng khác là có một lớp chỉ thực hiện giao diện ô tô, hãy gọi nó là AbstractCar và triển khai phương thức move(). Bây giờ những chiếc xe khác cũng thực hiện giao diện Xe, trong nội bộ chúng tạo ra một thể hiện của AbstractCar và chúng thực hiện phương thức move() của riêng chúng bằng cách gọi move() trên Xe trừu tượng bên trong của chúng. Nhưng điều này sẽ không lãng phí tài nguyên cho không có gì (một phương thức gọi một phương thức khác - không sao, JIT có thể in mã, nhưng vẫn còn) và sử dụng bộ nhớ thừa để giữ các đối tượng bên trong, thậm chí bạn không cần phải thừa kế thực hiện? (sau khi tất cả các đối tượng cần nhiều bộ nhớ hơn là tổng của dữ liệu đóng gói) Cũng không phải là nó khó xử cho một lập trình viên để viết phương pháp giả như
public void move() {
abstractCarObject.move();
}
?
Bất cứ ai cũng có thể tưởng tượng một ý tưởng tốt hơn cách tránh kế thừa triển khai và vẫn có thể sử dụng lại mã theo cách dễ dàng?
Tôi không thích gọi nó là "giao diện thừa kế" nhưng "giao diện triển khai". Đó là một điều tôi thực sự thích từ ngôn ngữ Java, hai khái niệm khác nhau được đặt tên cho phù hợp. – Trap