2010-10-20 23 views

Trả lời

4

Trong Java, bất cứ khi nào bạn kế thừa từ một lớp, lớp mới của bạn cũng sẽ tự động trở thành một loại phụ của loại lớp gốc. Vì đây là loại phụ nên cần tuân theo Liskov substitution principle.
Nguyên tắc này về cơ bản nói rằng bạn phải có khả năng sử dụng loại phụ ở bất kỳ nơi nào siêu kiểu được mong đợi. Điều này hạn chế nghiêm trọng cách hoạt động của lớp thừa kế mới của bạn có thể khác với lớp gốc.
Không trình biên dịch nào có thể khiến bạn tuân thủ nguyên tắc này, nhưng bạn có thể gặp rắc rối nếu không, đặc biệt khi các lập trình viên khác đang sử dụng các lớp của bạn.

Trong các ngôn ngữ cho phép phân lớp phụ mà không có phân loại phụ (như CZ language), quy tắc "Thành phần đối tượng ưu tiên thừa kế" không quan trọng bằng các ngôn ngữ như Java hoặc C#.

+0

>> Nếu bạn đang lập trình bằng ngôn ngữ cho phép phân lớp phụ mà không có phân loại phụ, bạn có nghĩa là ngôn ngữ kịch bản nhất? – Howard

+2

Tôi thích tác giả của câu hỏi cho thấy ông muốn nhận câu trả lời ngược lại với những gì được hỏi. Chúng tôi được yêu cầu cung cấp một ví dụ truy cập, nơi mà thừa kế sẽ phù hợp hơn. Tuy nhiên, anh ta phải từ bỏ và chấp nhận một ví dụ nữa, nơi mà thừa kế lại hút. Đây là một bí ẩn. OOP thống trị thế giới, tuy nhiên, tính năng chính của nó, thừa kế, không bao giờ được sử dụng trong lợi của thành phần cấu trúc tốt cũ! Có lẽ chúng ta nên thích các điều kiện trên đa hình cũng bởi vì đa hình là đạt được thông qua (luôn luôn) thừa kế xấu trong java? – Val

+1

Có thể Java cũng là rác vì dựa trên những thứ như Integer mở rộng Number và ByteInputStream mở rộng InputStream và mọi đối tượng đều lấy ra các phương thức khóa, băm và bình đẳng từ Object. Rõ ràng, nếu thừa kế bất cứ điều gì là xấu, sau đó java là sai từ ngay từ đầu. – Val

11

Thừa kế thích hợp cho các mối quan hệ is-a. Nó phù hợp cho mối quan hệ has-a.

Vì hầu hết các mối quan hệ giữa các lớp/thành phần rơi vào xô has-a (ví dụ, một lớp Car có thể không phải là một HashMap, nhưng nó có thể có một HashMap), nó sau đó sau thành phần thường là một ý tưởng tốt hơn cho mối quan hệ người mẫu giữa các lớp chứ không phải là thừa kế.

Đây không phải là để nói tuy nhiên rằng kế thừa không hữu ích hoặc không phải là giải pháp chính xác cho một số tình huống.

7

Câu trả lời đơn giản của tôi là bạn nên sử dụng thừa kế cho mục đích hành vi. Các lớp con nên ghi đè lên các phương thức để thay đổi hành vi của phương thức và chính đối tượng đó.

Bài viết này (cuộc phỏng vấn với Erich Gamma, một trong những GoF) nêu rõ lý do tại sao Favor object composition over class inheritance.

0

Chỉ cần nghĩ về nó như có một "is-a" hoặc "có-một" mối quan hệ

Trong ví dụ này Human "is-a" Animal, và nó có thể được thừa hưởng dữ liệu khác nhau từ lớp Animal. Do đó Thừa kế được sử dụng:

abstract class Animal { 
    private String name; 
    public String getName(){ 
     return name; 
    } 
    abstract int getLegCount(); 
} 

class Dog extends Animal{ 
    public int getLegCount(){ 
     return 4; 
    } 
} 

class Human extends Animal{ 
    public int getLegCount(){ 
     return 2; 
    } 
} 

Thành phần có ý nghĩa nếu một đối tượng là chủ sở hữu của đối tượng khác. Giống như một đối tượng con người sở hữu một đối tượng Dog. Vì vậy, trong ví dụ sau một đối tượng Nhân "có-một" Dog đối tượng

class Dog{ 
    private String name; 
} 
class Human{ 
    private Dog pet; 
} 

hy vọng rằng giúp ...

0

Đó là một nguyên tắc thiết kế cơ bản của một OOD tốt. Bạn có thể gán một hành vi cho một lớp năng động "trong thời gian chạy", nếu bạn sử dụng bố cục trong thiết kế của bạn chứ không phải là thừa kế như trong Mẫu chiến lược. Nói,

interface Xable { 
doSomething(); 
} 

class Aable implements Xable { doSomething() { /* behave like A */ } } 
class Bable implements Xable { doSomething() { /* behave like B */ } } 

class Bar { 
Xable ability; 

public void setAbility(XAble a) { ability = a; } 

public void behave() { 
ability.doSomething(); 
} 

} 
/*now we can set our ability in runtime dynamicly */ 

/*somewhere in your code */ 

Bar bar = new Bar(); 
bar.setAbility(new Aable()); 
bar.behave(); /* behaves like A*/ 
bar.setAbility(new Bable()); 
bar.behave(); /* behaves like B*/ 

nếu bạn đã sử dụng thừa kế, "Bar" sẽ nhận được hành vi "tĩnh" trên thừa kế.

1

Thừa kế cho phép một đối tượng của kiểu dẫn xuất được sử dụng trong hầu hết mọi trường hợp mà người ta sẽ sử dụng một đối tượng của loại cơ sở. Thành phần không cho phép điều này. Sử dụng thừa kế khi cần thay thế như vậy và bố cục khi nó không được.

0

Thừa kế là cần thiết cho phân loại. Xem xét:

class Base { 
    void Foo() { /* ... */ } 
    void Bar() { /* ... */ } 
} 

class Composed { 
    void Foo() { mBase.Foo(); } 
    void Bar() { mBase.Foo(); } 
    private Base mBase; 
} 

Mặc dù Composed hỗ trợ tất cả các phương pháp Foo nó không thể được truyền cho một chức năng mà hy vọng một giá trị kiểu Foo:

void TakeBase(Base b) { /* ... */ } 

TakeBase(new Composed()); // ERROR 

Vì vậy, nếu bạn muốn đa hình, bạn cần thừa kế (hoặc thực hiện giao diện người anh em họ của nó).

Các vấn đề liên quan