Làm thế nào tôi có thể giải thích sự hữu ích của Kế thừa? [đóng cửa]


16

Khi cố gắng giải thích khái niệm Kế thừa trong OOP, ví dụ phổ biến thường là ví dụ về động vật có vú. IMHO, đây thực sự là một ví dụ tồi, bởi vì nó sẽ dẫn người mới sử dụng khái niệm này sai cách. Và hơn nữa, nó không phải là một thiết kế phổ biến mà họ sẽ phải đối mặt trong công việc thiết kế hàng ngày của họ.

Vì vậy, điều gì sẽ là một vấn đề tốt đẹp, đơn giản và cụ thể được giải quyết bằng cách sử dụng Kế thừa?


1
"Ví dụ phổ biến thường là động vật có vú"? Ý anh là gì? Bạn có thể cung cấp một liên kết, tài liệu tham khảo hoặc trích dẫn cho điều này?
S.Lott


3
Điều gì sẽ là ví dụ thực tế tốt nhất để giải thích sự hữu ích của Kế thừa = quỹ ủy thác trẻ em của Bill Gates?
Martin Beckett

1
@Chris: làm thế nào là câu hỏi này không mang tính xây dựng? Bạn đang tuyên bố rằng một người hỏi và 14 người trả lời đang lãng phí thời gian của mọi người?
Dan Dascalescu 6/2/2015

@DanDascalescu - nó đã bị đóng cửa hai năm trước để phản hồi lại một lá cờ nêu rõ "vui lòng xem xét việc đóng cửa là không mang tính xây dựng: đánh giá bằng cách trả lời trên đó, đây giống như một câu hỏi thăm dò / danh sách điển hình". Nếu bạn nghĩ rằng điều này là sai, hãy chỉnh sửa nó để làm rõ rằng nó không phải và để cộng đồng quyết định thông qua hàng đợi đánh giá mở lại.
ChrisF

Câu trả lời:


15

Không có gì sai với một ví dụ học thuật thuần túy như động vật có vú. Tôi cũng thích ví dụ hình chữ nhật / hình vuông vì nó chỉ ra lý do tại sao các nguyên tắc phân loại trong thế giới thực không luôn luôn trực tiếp chuyển sang mối quan hệ thừa kế mà bạn mong đợi.

Theo tôi, ví dụ điển hình nhất mỗi ngày là bộ công cụ GUI. Đó là thứ mà mọi người đã sử dụng, nhưng những người mới bắt đầu có thể không có lý do về cách họ làm việc dưới mui xe. Bạn có thể nói về những hành vi phổ biến đối với tất cả các container, tất cả các vật dụng, sự kiện, v.v. mà không đòi hỏi kiến ​​thức chi tiết về bất kỳ triển khai nào.


5
+1 cho bộ công cụ GUI ... và tôi cũng thích ví dụ về hình dạng, với một Hình dạng làm cơ sở với hình vẽ tối thiểu () và hình dạng con cháu với hình vẽ () tùy chỉnh.
yati sagade

14

Ví dụ thực tế của tôi là mô hình miền của một ứng dụng nhân sự đơn giản. Tôi nói rằng chúng ta có thể tạo một lớp cơ sở gọi là Nhân viên , vì tất nhiên, người quản lý cũng là nhân viên.

public class Employee
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Code { get; set; }

    public string GetInsuranceHistory()
    {
        // Retrieving insurance history based on employee code.
    }
}

Sau đó tôi giải thích rằng các nhà phát triểnnhân viên , người thử nghiệmnhân viên , người quản lý dự ánnhân viên . Do đó tất cả họ có thể kế thừa từ lớp nhân viên.


2
Để thể hiện lợi thế thừa kế, cũng có thể thú vị khi chỉ ra các nhà phát triển khác với nhân viên như thế nào. Nếu không có sự khác biệt, thì không cần phải tạo lớp Nhà phát triển.
David

3
Có vẻ như Employeecó thể là một abstractlớp quá.
StuperUser

+1 đây là ví dụ hầu hết các giáo viên của tôi đã sử dụng và tôi thực sự thích nó. nó hoàn toàn có ý nghĩa và đưa ra một ví dụ thực tế về cách sử dụng tính kế thừa.
David Peterman

18
Ngoại trừ điều này không bao giờ hoạt động trong thực tế bởi vì luôn có ít nhất một người cần phải có cả a Developervà a Tester. Một tình huống tương tự khác là một cơ sở dữ liệu liên hệ nơi bạn có CustomerSupplier, nhưng bất kỳ ai đã tạo ra một hệ thống như vậy sẽ cho bạn biết, luôn có một trường hợp Companylà cả hai. Đó là lý do tại sao hầu hết các ví dụ này dẫn bạn đi sai hướng.
Scott Whitlock

11

Đóng gói những gì khác nhau ... hiển thị cho họ một mẫu phương thức mẫu , nó thể hiện tính hữu ích của kế thừa bằng cách đặt hành vi chung trong một lớp cơ sở và gói gọn hành vi khác nhau trong các lớp con.

UI controlsStreamscũng là một ví dụ rất tốt cho sự hữu ích của thừa kế.


Tôi nghĩ rằng nhà máy sẽ là một ví dụ tốt hơn.
Let_Me_Be

1
@Let_Me_Be: Tôi nghĩ rằng mối quan hệ giữa nhà máy và quyền thừa kế về bản chất là quá gián tiếp. Chắc chắn, nó tạo ra các loại cụ thể và trả về các loại trừu tượng / cơ sở, nhưng nó cũng có thể trả về chỉ là một loại giao diện! Imho không tốt hơn ví dụ động vật cổ điển.
Falcon

@Let_Me_Be: Ngoài ra, một nhà máy trừu tượng là một ví dụ khá phức tạp liên quan đến các hệ thống phân cấp thừa kế khác nhau (một cho các mục, một cho các nhà máy). Tôi nghĩ rằng đó là một cách sử dụng tốt của thừa kế, nhưng không phải là một ví dụ tốt và đơn giản.
Falcon

3

Nhớ lại

Mỗi ví dụ của một đối tượng là một ví dụ cụ thể về tính hữu ích của thừa kế!

Nếu bạn có nghĩa là kế thừa lớp cụ thể , thì bây giờ bạn đang ở trong thế giới của các nguyên tắc phân loại, và những thứ đó sẽ thay đổi mạnh mẽ bởi các mục tiêu của hệ thống sử dụng chúng. Ví dụ về động vật / động vật có vú sử dụng một phân loại phổ biến và hy vọng quen thuộc từ sinh học, nhưng nó (như bạn đã đề cập) gần như vô dụng đối với phần lớn các vấn đề lập trình.

Vì vậy, hãy thử một cái gì đó phổ quát: khái niệm về một chương trình. Mỗi chương trình bắt đầu, chạy và kết thúc. Mỗi chương trình có một tên và các tham số dòng lệnh tùy chọn. Vì vậy, một lớp Chương trình cơ sở sẽ rất hữu ích, để bắt đầu thực thi, lấy và xử lý các đối số dòng lệnh, chạy logic chính và tắt một cách duyên dáng.

Đó là lý do tại sao rất nhiều ngôn ngữ lập trình hướng đối tượng cung cấp một lớp Chương trình hoặc một cái gì đó hoạt động chính xác như một lớp Chương trình.


Vì vậy, bạn lập trình một chương trình có nhiều chương trình trong đó? :) Theo kinh nghiệm của tôi, các Đối tượng Chương trình hầu như luôn luôn là những người độc thân không có sự kế thừa, vì vậy imho chúng không phải là ví dụ tốt nhất.
keppla

@keppla: bạn đã bao giờ sử dụng Java hay .NET chưa? .NET có một lớp Chương trình rõ ràng, Java là ẩn. Họ không phải là người độc thân
Steven A. Lowe

tôi đã sử dụng Java, khoảng phiên bản 1.4.2. Trước đó, chỉ có khoảng trống tĩnh chính, vì vậy tôi đoán nó đã thay đổi một chút. Điều gì sẽ là một lý do điển hình để có nhiều hơn một thể hiện của lớp Programm?
keppla

@keppla: java void void chính làm cho lớp mục nhập đại diện cho chương trình. Mỗi người dùng chạy chương trình của bạn tạo ra một phiên bản mới của nó. Tại thời điểm này, tôi có ba phiên bản Google Chrome đang chạy, bốn tài liệu Word, ba Notepad và hai Nhà thám hiểm Windows. Nếu họ là tất cả những người độc thân, tôi sẽ không bao giờ có thể làm điều đó.
Steven A. Lowe

1
tôi nghĩ rằng bạn kéo dài định nghĩa một chút. class Programm { public static void main(String[] args) { system.out.println('hello world'); }}là một chương trình Java tối thiểu. Khi tôi gọi nó, không có phiên bản nào của Chương trình. Chương trình không kế thừa từ bất cứ điều gì. Khi tôi bắt đầu 3 Quá trình (giống như bạn làm với crhome), có thể có 3 Chương trình, nhưng trong các vùng bộ nhớ riêng lẻ của chúng, vẫn chỉ có một Chương trình. Imho, singleton ngụ ý 'Chỉ một trường hợp trên mỗi quy trình', không phải cho mỗi Máy. Nếu vậy, sẽ không thể tạo ra singletons, không có gì ngăn bạn chạy bất kỳ mã nào hai lần.
keppla

3

Tôi đang làm việc với máy ảnh tại nơi làm việc. Chúng tôi có các thiết bị kết nối với các kiểu máy khác nhau, vì vậy chúng tôi có một "lớp máy ảnh" trừu tượng và mọi kiểu máy đều được thừa hưởng từ lớp này để hỗ trợ chức năng cụ thể của máy ảnh đó. Đó là một ví dụ thực tế và không khó hiểu.


2
Điều này có thể bị hỏng nếu bạn có, ví dụ như một mô hình cả a Cameravà a Phone(như tất cả chúng ta hiện đang làm trong túi của mình). Nó nên kế thừa lớp cơ sở nào? Hoặc không nên chỉ thực hiện cả giao diện ICameraIPhonegiao diện? (ha ha)
Scott Whitlock

2
@Scott: Bạn không thể triển khai giao diện IPhone hoặc bạn sẽ bị Apple kiện.
Mason Wheeler

3

Ví dụ hóa học

Đây là một ví dụ khác xuất hiện trong não tôi:

lớp Element_
{
    nguyên tử đôi; // Trọng lượng nguyên tử của nguyên tố
    số nguyên tử kép; // Số nguyên tử của nguyên tố
    Thuộc tính chuỗi; // Thuộc tính của phần tử
    // Những người khác, nếu có
}


lớp Đồng vị mở rộng Element_ // Có thể tồn tại Đồng vị của phần tử
{
    gấp đôi nửa đời;
   // Khác nếu có

}

2
Mặc dù nguyên tử có thể (nên?) Có thể là số nguyên ...
Andrew

Tôi sẽ không sử dụng thừa kế cho điều đó. isotopekhông phải là một trường hợp đặc biệt của Elemenet. Tôi muốn có một Elementtài sản trên Isotope.
CodeInChaos

2

Các ví dụ trong thế giới thực hầu như luôn hiểu sai bởi vì họ đưa ra các ví dụ trong đó luôn có khả năng có một thứ gì đó là cả TypeATypeBnhưng hệ thống phân cấp thừa kế duy nhất của nhiều ngôn ngữ không cho phép điều đó.

Tôi càng lập trình, tôi càng tránh xa sự kế thừa.

Ngay cả từ "thừa kế" cũng được sử dụng không đúng cách ở đây. Chẳng hạn, bạn thừa hưởng khoảng 50% tính trạng của cha và 50% tính trạng của mẹ. Thực sự DNA của bạn là một thành phần của một nửa DNA của cha bạn và một nửa DNA của mẹ bạn. Đó là bởi vì sinh học thực sự ủng hộ thành phần hơn sự kế thừa , và bạn cũng vậy.

Đơn giản chỉ cần thực hiện các giao diện, hoặc thậm chí tốt hơn, "gõ vịt", cộng với tiêm phụ thuộc, là một điều tốt hơn nhiều để dạy cho những người mới biết lập trình hướng đối tượng.


1

Tôi chỉ cho họ thấy một ví dụ thực tế. Ví dụ, trong hầu hết các khung UI, bạn xuất phát từ một loại lớp "Hộp thoại" hoặc "Cửa sổ" hoặc "Điều khiển" để tạo riêng cho bạn.


1

Ví dụ điển hình là hàm so sánh trong sắp xếp:

template<class T>
class CompareInterface {
public:
   virtual bool Compare(T t1, T t2) const=0;
};
class FloatCompare : public CompareInterface<float> { };
class CompareImplementation : public FloatCompare {
public:
   bool Compare(float t1, float t2) const { return t1<t2; }
};
template<class T>
void Sort(T*array, int size, CompareInterface<T> &compare);

Vấn đề duy nhất là những người mới quá thường nghĩ rằng hiệu suất quan trọng hơn mã tốt ...


0

Ví dụ thế giới thực của tôi là một chiếc xe:

public class Vehicle
{
    public Vehicle(int doors, int wheels)
    {
        // I describe things that should be
        // established and "unchangeable" 
        // when the class is first "made"
        NumberOfDoors = doors;
        NumberOfWheels = wheels;
    }

    public void RollWindowsUp()
    {
        WindowsUp = true;
    }

    // I cover modifiers on properties to show
    // how to protect certain things from being
    // overridden
    public int NumberOfDoors { get; private set; }
    public int NumberOfWheels { get; private set; }

    public string Color { get; set; }
    public bool WindowsUp { get; set; }
    public int Speed { get; set; }
}

public class Car : Vehicle
{
    public Car : base(4, 4)
    {

    }
}

public class SemiTruck : Vehicle
{
    public SemiTruck : base(2, 18)
    {

    }
}

Ví dụ này có thể có được chi tiết như bạn muốn, và có tất cả các loại thuộc tính được gắn vào xe để giải thích việc sử dụng bất kỳ sửa đổi nào bạn có thể muốn dạy.


2
Tôi luôn ghét sử dụng các phương tiện làm ví dụ, vì nó không giúp một lập trình viên mới gần gũi hơn để hiểu cách kế thừa có thể được sử dụng để cải thiện mã. Xe cộ là những cỗ máy vô cùng phức tạp, gợi lên rất nhiều ý tưởng không trừu tượng trong tâm trí của người không lập trình. Cố gắng mô tả điều này trong mã làm cho người mới trung bình tin rằng có rất nhiều chi tiết bị bỏ qua ví dụ và mang lại cảm giác rằng họ không còn gần gũi hơn để làm việc gì đó. Tôi nói điều này từ kinh nghiệm, vì đó chính xác là cảm giác của tôi khi ai đó cố gắng sử dụng phương tiện để giải thích cho tôi.
riwalk

@ Stargazer712: Tôi sử dụng phương tiện chủ yếu vì chúng có thể phức tạp hoặc đơn giản như bạn muốn. Tôi để nó cho phán quyết của người hướng dẫn để xác định mức độ học sinh của mình. Tôi đã giải thích OOP cơ bản cho vợ tôi (người không có kinh nghiệm lập trình) bằng cách sử dụng các thuộc tính đơn giản của một chiếc xe mô tả những điều cơ bản chung. Tất cả các phương tiện đều có cửa, tất cả các phương tiện đều có bánh xe, v.v ... Ví dụ về đối tượng không thể đổ lỗi cho một kế hoạch bài học kém.
Joel Etherton

Vợ bạn không cố viết mã. Tôi rất có thể nói rằng các ví dụ về xe cộ không làm gì để giúp tôi hiểu về quyền thừa kế. Bất cứ điều gì bạn sử dụng để mô tả sự kế thừa, nó phải đầy đủthiết thực . Mục tiêu không phải là mô tả nó theo cách mà một người không lập trình có thể hiểu nó. Mục tiêu là mô tả nó theo cách mà một lập trình viên mới có thể sử dụng nó, và cách duy nhất để làm điều đó là hiển thị các ví dụ mới về cách một lập trình viên chuyên nghiệp sẽ sử dụng nó.
riwalk

@ Stargazer712: Tôi sẽ đặt sự bất lực của bạn ban đầu để hiểu sự kế thừa vào một kế hoạch bài học kém. Tôi cũng đã sử dụng phương tiện để giải thích quyền thừa kế cho các đàn em mà tôi làm việc cùng, và tôi chưa bao giờ gặp vấn đề với khái niệm này. Theo tôi, nếu một kế hoạch bài học được xây dựng kỹ lưỡng và đúng đắn, một đối tượng phương tiện là hoàn chỉnh và thực tế. 1 anh chàng ngẫu nhiên trên internet sẽ không thay đổi điều đó khi đối mặt với khoảng 30 thực tập sinh và các nhà phát triển cơ sở mà tôi đã dạy OOP. Nếu bạn không thích phương tiện này, hãy bỏ phiếu và tiếp tục.
Joel Etherton

Như bạn muốn ....
riwalk

0

Ví dụ không phải động vật có vú, không phải chim, không phải cá này có thể giúp:

public abstract class Person {

    /* this contains thing all persons have, like name, gender, home addr, etc. */

    public Object getHomeAddr() { ... }

    public Person getName() { ... }

}

public class Employee extends Person{

    /* It adds things like date of contract, salary, position, etc */

    public Object getAccount() { ... }

}

public abstract class Patient extends Person {
    /* It adds things like medical history, etc */
}

Sau đó

public static void main(String[] args) {

    /* you can send Xmas cards to patients and employees home addresses */

    List<Person> employeesAndPatients = Factory.getListOfEmployeesAndPatients();

    for (Person p: employeesAndPatients){
        sendXmasCard(p.getName(),p.getHomeAddr());
    }

    /* or you can proccess payment to employees */

    List<Employee> employees = Factory.getListOfEmployees();

    for (Employee e: employees){
        proccessPayment(e.getName(),e.getAccount());
    }       

}

LƯU Ý: Chỉ cần không nói bí mật: Người kéo dài Động vật có vú.


1
Làm việc cho đến khi một nhân viên của bạn cũng là một bệnh nhân.
Scott Whitlock

Trong trường hợp này, tôi nghĩ sẽ hợp lý hơn khi tuyên bố Bệnh nhân và Nhân viên là các giao diện thay vì các lớp trừu tượng. Điều đó cho phép bạn linh hoạt khi có Person thực hiện nhiều giao diện.
Jin Kim

@JinKim - Tôi hoàn toàn đồng ý, đó là cách tiếp cận tốt hơn.
Scott Whitlock

@JinKim Họ không độc quyền. Bạn đối xử với một người như một nhân viên hoặc một bệnh nhân tại bất kỳ thời điểm nào, nhưng không phải cùng một lúc. Hai giao diện là OK nhưng sau đó khi nào bạn gọi một lớp cụ thể thực hiện cả hai, EmployeePatient? Bạn sẽ có bao nhiêu kết hợp?
Tulains Córdova

Bạn có thể gọi lớp cụ thể bất cứ điều gì bạn muốn. Nếu mã chỉ mong muốn giao dịch với Nhân viên, bạn khai báo tham chiếu là Nhân viên. (tức là nhân viên nhân viên = người mới ();) Nếu mã chỉ mong muốn giao dịch với Bệnh nhân, bạn khai báo tham chiếu là Bệnh nhân. Hiếm khi bạn muốn khai báo một tham chiếu trực tiếp như là lớp cụ thể.
Jin Kim

0

Làm thế nào về một hệ thống phân cấp các biểu thức đại số. Là tốt bởi vì nó bao gồm cả thừa kế và thành phần:

+--------------------+------------------------+
| Expression         |<------------------+    |
+--------------------+----------+        |    |
| + evaluate(): int  |<---+     |        |    |
+--------------------+    |     |        |    |
          ^               |     |        |    |
          |               |     |        |    |
   +--------------+  +---------------+  +-------------+  ...
   | Constant     |  | Negation      |  | Addition    |
   +--------------+  +---------------+  +-------------+
   | -value: int  |  |               |  |             |
   +--------------+  +---------------+  +-------------+
   | +evaluate()  |  | +evaluate()   |  | +evaluate() |
   | +toString()  |  | +toString()   |  | +toString() |
   +--------------+  +---------------+  +-------------+

   Addition(Constant(5), Negation(Addition(Constant(3),Constant(2))))
   (5 + -(3 + 2)) = 0

Ngoại trừ biểu thức gốc Hằng, tất cả các biểu thức khác đều là Biểu thức và chứa một hoặc nhiều biểu thức.


-1

Tôi sẽ sử dụng chim làm ví dụ

như gà, vịt, đại bàng

Tôi sẽ giải thích cả hai đều có móng vuốt, mổ và cánh nhưng thuộc tính của chúng là khác nhau.

Gà không thể bay, không biết bơi, có thể ăn giun, có thể ăn ngũ cốc

Vịt không thể bay, có thể bơi, có thể ăn ngũ cốc, không thể ăn giun

Đại bàng có thể bay, không thể bơi, có thể ăn giun, không thể ăn ngũ cốc


4
Tôi đã từng đọc rằng bố cục và giao diện có lẽ là cách tốt nhất để truyền đạt loại khái niệm này, ví dụ như bay, bơi, v.v.
dreza

Một con vịt không thể bay?!
Adam Cameron

-3

Rails-clone điển hình của bạn cung cấp nhiều ví dụ thực tế : bạn có lớp mô hình cơ sở (trừu tượng), đóng gói tất cả các thao tác dữ liệu và bạn có lớp trình điều khiển cơ sở, đóng gói tất cả giao tiếp HTTP.


Quan tâm để giải thích tại sao câu trả lời này là xấu?
keppla
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.