2013-04-05 39 views
18

Giả sử tôi có hai lớp: Động vật và Chó. Chó là một phân lớp của Động vật. Tôi làm như sau:Đa hình vs Thừa kế

Animal a = new Dog(); 

Bây giờ tôi có thể gọi các phương thức của lớp Dog thông qua một biến.

Nhưng câu hỏi của tôi là: nếu tôi có thể gọi tất cả các phương pháp của Animal thông qua các đối tượng Dog (thừa kế) hơn lý do tại sao tôi nên sử dụng nguyên lý đa hình? Tôi chỉ có thể tuyên bố:

Dog d = new Dog(); 

Với tuyên bố này có thể sử dụng tất cả các phương pháp của Thú và phương pháp Dog. Vậy tại sao sử dụng đa hình? Cảm ơn bạn rất nhiều vì câu trả lời của bạn.

+1

Tiêu đề của câu hỏi ("Đa hình so với thừa kế") sai theo định nghĩa :) – Poni

+0

có thể trùng lặp của [Sự khác nhau chính giữa Thừa kế và đa hình là gì?] (Http://stackoverflow.com/questions/6308178/what- là sự khác biệt chính-giữa-thừa kế và đa hình) – tstew

Trả lời

23

Trong Java, các khái niệm về đa hình và thừa kế được "hàn lại với nhau"; nói chung, nó không phải là cách mà:

  • Polymorphism cho phép bạn gọi các phương thức của một lớp mà không biết chính xác loại lớp
  • thừa kế cho phép có nguồn gốc lớp học phần giao diện và mã của các lớp cơ sở của họ

có những ngôn ngữ nơi thừa kế được tách rời từ polymorphism:

  • Trong C++ bạn có thể kế thừa một lớp học mà không tạo ra hành vi đa hình (tức là không các hàm đánh dấu trong lớp cơ sở với virtual)
  • Trong mục tiêu C bạn có thể thực hiện một phương thức trên một lớp không liên quan và gọi nó từ một nơi chỉ biết chữ ký của phương thức.

Quay lại Java, lý do sử dụng đa hình là tách mã của bạn khỏi chi tiết về việc thực hiện các đối tác của nó: ví dụ: nếu bạn có thể viết phương pháp Feed(Animal animal) hoạt động cho tất cả các loại động vật, phương pháp này sẽ vẫn áp dụng được khi bạn thêm các lớp con hoặc triển khai khác của Animal.Điều này trái ngược với phương pháp Feed(Dog dog), sẽ được kết hợp chặt chẽ với chó.

Theo như tuyên bố

Dog d = new Dog(); 

đi, không có lý do chung để tránh điều này nếu bạn biết rằng phần còn lại của giao dịch phương pháp của bạn đặc biệt với những con chó. Tuy nhiên, trong nhiều trường hợp, sau đó không phải là trường hợp: ví dụ, lớp học của bạn hoặc các phương pháp của bạn sẽ thường không nhạy cảm với việc thực hiện chính xác, ví dụ

List<Integer> numbers = new ArrayList<Integer>(); 

Trong những trường hợp như vậy, bạn có thể thay new ArrayList<Integer>() với new LinkedList<Integer>(), và biết rằng mã của bạn sẽ biên dịch. Ngược lại, có danh sách numbers của bạn được khai báo là ArrayList<Integer> numbers, việc chuyển đổi như vậy có thể không chắc chắn.

Điều này được gọi là "lập trình cho giao diện". Có rất tốt answer trên Stack Overflow giải thích nó.

+1

Cảm ơn bạn rất nhiều, giải thích tuyệt vời. – Alan

4

Bạn có thể có các triển khai khác của lớp Animal, chẳng hạn như Cat. Sau đó, bạn có thể nói

Animal a = new Dog(); 
Animal b = new Cat(); 

Bạn có thể gọi các phương thức của lớp Animal mà không cần chăm sóc mà thực hiện nó thực sự là, và sẽ gọi phương thức chính xác. Ví dụ.

a.speak(); // "Woof" 

b.speak(); // "Meow" 

Thực sự, nó không phải là "Đa hình so với Thừa kế" nhưng "Đa hình sử dụng Thừa kế".

+0

Đầu tiên, cảm ơn bạn đã trả lời. Nhưng tôi vẫn không hiểu tại sao tôi không nên tuyên bố: Dog d = new Dog(); thay vì sử dụng Animal a = new Dog() ;. Tôi vẫn có thể sử dụng tất cả các phương pháp của Animal, phải không? – Alan

+0

Nếu bạn cần chức năng 'Dog' cụ thể, sau đó bằng mọi cách sử dụng' Dog d = new Dog() '. Vui lòng xem câu trả lời của @ NPE về thời điểm bạn chỉ cần chức năng 'Động vật cụ thể'. Mã đó sẽ làm việc cho bất kỳ việc thực hiện 'Động vật' nào. – rgettman

+0

Cảm ơn bạn! :) nó rất hữu ích. – Alan

4

Polymorphism cho phép bạn viết một phương pháp mà làm việc cho bất kỳ Animal:

public void pet(Animal animal) { 
    ... 
} 

Phương pháp này sẽ chấp nhận Dog, Cat, vv, trong đó có các lớp con của Animal mà vẫn chưa được viết ra.

Nếu phương pháp này là để tận Dog, nó sẽ không làm việc cho Cat, vv

+0

Đầu tiên, cảm ơn bạn đã trả lời. Nhưng tôi vẫn không hiểu tại sao tôi không nên tuyên bố: Dog d = new Dog(); thay vì sử dụng Animal a = new Dog() ;. Tôi vẫn có thể sử dụng tất cả các phương pháp của Animal, phải không? – Alan

1

Nếu bạn chắc chắn rằng nó sẽ luôn là một con chó, không có lý do gì cho nó. Bạn cũng có thể sử dụng Dog d = new Dog(); như bạn đã mô tả. Nhưng giả sử bạn đã sử dụng một phương thức thay vì một hàm tạo. Phương pháp này trả về một con vật và bạn sẽ không biết bạn sẽ nhận được động vật nào. Bạn vẫn có thể sử dụng cùng một phương pháp trên động vật (ngay cả khi đó là Chó, Voi mèo, v.v.).

Để thừa kế mục đích mở rộng, đơn giản hóa mọi thứ. Khi bạn muốn tạo ra một con voi hoặc con mèo mà cũng chia sẻ một số phương pháp động vật, bạn có thể dễ dàng có được những người bằng cách có động vật như lớp siêu.

+1

Cảm ơn bạn rất nhiều! – Alan

0

Thông thường câu hỏi bạn đã hỏi tương tự như Thừa kế vs Thành phần :) Ví dụ "thực tế" về lý do tại sao việc sử dụng đa hình là tốt cho ví dụ sử dụng mẫu thiết kế chiến lược. Bạn có thể có nhiều triển khai TaxPolicy: UsaTaxPolicy, CanadaTaxPolicy, EuTaxPolicy, v.v. Nếu bạn có phương pháp tính toánFinalPrice, cũng phải tính thuế, sau đó bạn thực thi đúng và tính toán tốt được thực hiện, bất kể bạn đã vượt qua Hoa Kỳ, Canada hay Eu thực hiện.

0

thừa kế là đa hình động. Tôi có nghĩa là khi bạn loại bỏ thừa kế, bạn không thể ghi đè lên nữa.