"Xin chào, Amigo! Bây giờ đây là chủ đề tôi nghĩ bạn sẽ sử dụng nhiều. Tôi đang nói về quyền thừa kế. "

Đối với những người không quen biết, lập trình giống như ma thuật. Vì vậy, hãy để tôi bắt đầu với một phép loại suy…

Giả sử bạn là một ảo thuật gia muốn tạo ra một con ngựa bay. Bạn có thể thử triệu hồi một Pegasus. Nhưng vì ngựa bay không tự nhiên xuất hiện nên bạn sẽ gặp rất nhiều khó khăn. Bạn sẽ có rất nhiều việc phải làm. Sẽ dễ dàng hơn nhiều nếu bắt đầu với một con ngựa và triệu hồi một số đôi cánh.

Di sản.  Ưu điểm của thừa kế - 1

Trong lập trình, chúng tôi gọi quá trình này là «kế thừa» . Giả sử bạn cần viết một lớp rất phức tạp. Bạn có thể dành nhiều thời gian để viết mã từ đầu, sau đó thực hiện kiểm tra dài để tìm lỗi. Nhưng tại sao làm điều đó một cách khó khăn? Tốt hơn hết là bạn nên nhìn xung quanh và xem lớp học bạn đang tìm kiếm đã tồn tại chưa?

Giả sử bạn tìm thấy một lớp thực hiện 80% chức năng mà bạn cần. Bạn chỉ có thể sao chép mã của nó vào lớp học của mình. Nhưng điều đó sẽ có một số nhược điểm:

1) Lớp bạn tìm thấy có thể đã được biên dịch thành mã byte. Bạn có thể không có quyền truy cập vào mã nguồn của nó.

2) Bạn có thể có mã nguồn của lớp, nhưng cũng có thể làm việc tại một công ty có thể bị kiện vài tỷ nếu bạn sử dụng dù chỉ 6 dòng mã của người khác. Và sau đó họ sẽ kiện bạn.

3) Điều này dẫn đến việc sao chép rất nhiều mã không cần thiết. Và nếu tác giả của lớp khác tìm thấy lỗi và sửa nó, bạn vẫn có lỗi.

Có một giải pháp tao nhã hơn mà không yêu cầu phải có sự cho phép hợp pháp đối với mã của lớp ban đầu. Trong Java, bạn có thể chỉ cần khai báo lớp khác là cha của lớp bạn. Điều này tương đương với việc thêm mã của lớp đó vào lớp của chính bạn. Tất cả dữ liệu và phương thức của lớp cha sẽ xuất hiện trong lớp của bạn. Ví dụ: bạn có thể kế thừa từ «ngựa», thêm «cánh» và nhận «Pegasus».

Di sản.  Ưu điểm của thừa kế - 2

"Rất thú vị. Xin hãy tiếp tục."

"Kế thừa cũng có những cách sử dụng khác. Giả sử bạn có mười lớp rất giống nhau. Chúng có dữ liệu và phương thức phù hợp. Bạn có thể tạo một lớp cơ sở đặc biệt , di chuyển dữ liệu (và các phương thức liên quan) sang lớp cơ sở và có mười lớp đó kế thừa từ nó. Nói cách khác, đối với mỗi lớp, bạn chỉ ra rằng nó có một lớp cha, còn được gọi là lớp cơ sở."

"Giống như những ưu điểm của tính trừu tượng chỉ thực sự được bộc lộ liên quan đến tính đóng gói, những ưu điểm của tính kế thừa được phóng đại nhờ tính đa hình. Nhưng tôi sẽ nói với bạn về điều đó vào ngày mai. Hôm nay chúng ta hãy xem xét một vài ví dụ về tính kế thừa."

"Giả sử chúng ta đang viết một chương trình cờ vua. Chúng ta cần các lớp học dành cho các quân cờ. Bạn sẽ đề xuất lớp học nào, Amigo?"

"Vua, Hậu, Giám mục, Hiệp sĩ, Xe và Tốt."

"Rất tốt. Anh không bỏ sót điều gì."

"Và dữ liệu nào bạn sẽ đề xuất lưu trữ trong các lớp này?"

"Vị trí của từng quân cờ (x và y) và giá trị. Xét cho cùng, một số quân cờ có giá trị hơn những quân cờ khác."

"Và sự khác biệt giữa các lớp này là gì?"

"Chúng khác nhau ở cách chúng di chuyển các quân cờ. Trong hành vi của chúng."

"Có. Bạn có thể định nghĩa chúng là các lớp như thế này:"

class King
{
int x;
int y;
int worth;
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen
{
int x;
int y;
int worth;
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook
{
int x;
int y;
int worth;
void rookMove()
{
//code that defines,
//how the rook moves
}
}
class Knight
{
int x;
int y;
int worth;
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop
{
int x;
int y;
int worth;
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn
{
int x;
int y;
int worth;
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"Vâng, đó chính xác là cách tôi sẽ viết nó."

"Nhưng hãy xem cách bạn có thể sử dụng tính kế thừa để viết ít mã hơn. Chúng ta có thể di chuyển các phương thức và dữ liệu giống hệt nhau vào một lớp chung. Hãy gọi nó là ChessItem. Tạo các đối tượng ChessItem không có ý nghĩa gì, vì chúng không tương ứng với bất kỳ quân cờ. Nhưng lớp học sẽ cực kỳ hữu ích:"

class King extends ChessItem
{
void kingMove()
{
//code that defines,
//how the king moves
}
}
class Queen extends ChessItem
{
void queenMove()
{
//code that defines,
//how the queen moves
}
}
class Rook extends ChessItem
{
void rookMove()
{
//code that defines,
//how the rook moves
}
}
 class ChessItem
{
int x;
int y;
int worth;
}
 
class Knight extends ChessItem
{
void knightMove()
{
//code that defines,
//how the knight moves
}
}
class Bishop extends ChessItem
{
void bishopMove()
{
//code that defines,
//how the bishop moves
}
}
class Pawn extends ChessItem
{
void pawnMove()
{
//code that defines,
//how the pawn moves
}
}

"Thật thú vị!"

"Chắc chắn rồi! Lợi ích đặc biệt lớn trong các dự án chứa hàng nghìn đối tượng khác nhau và hàng trăm lớp. Trong trường hợp này, các lớp được chọn đúng không chỉ có thể đơn giản hóa đáng kể logic mà còn giảm mã cần thiết xuống 10 lần."

"Vậy bạn phải làm gì để kế thừa một lớp?"

"Sau khi khai báo một lớp, chúng ta sử dụng từ khóa ' extend ', theo sau là tên của lớp cha. Bạn chỉ có thể kế thừa từ một lớp. "

Di sản.  Ưu điểm của thừa kế - 3

Bức ảnh cho thấy một "con bò" được thừa hưởng từ một con "lợn". «Lợn» kế thừa từ «gà», và «gà» kế thừa từ «trứng». Mỗi lớp chỉ có một phụ huynh! Sự kế thừa như vậy không phải lúc nào cũng hợp lý. Nếu bạn chỉ có một con lợn, nhưng bạn thực sự cần một con bò, các lập trình viên thường không thể cưỡng lại mong muốn tạo ra một con «bò» từ «con lợn».

"Nhưng nếu tôi muốn kế thừa từ hai lớp thì sao? Tôi có thể làm gì không?!"

"Không hẳn. Các lớp Java không hỗ trợ triển khai nhiều kế thừa: một lớp chỉ có thể có một lớp cha duy nhất. Nhưng có nhiều kiểu kế thừa, có nghĩa là một lớp có thể triển khai nhiều hơn một giao diện. Điều này giảm nhẹ vấn đề. "

"Tôi hiểu rồi. Và giao diện là gì?"

"Tôi sẽ nói với bạn về giao diện vào ngày mai. Bây giờ, hãy tiếp tục đào sâu vào kế thừa."