6.1 Kế thừa — đơn giản mà
Kế thừa là một khái niệm cơ bản trong lập trình hướng đối tượng (OOP), cho phép một lớp (gọi là lớp con hoặc subclass) kế thừa các thuộc tính và phương thức của một lớp khác (gọi là lớp cha hoặc superclass).
Cách tiếp cận này giúp tạo ra các lớp tổng quát hơn và tái sử dụng mã, cải thiện tổ chức và khả năng bảo trì mã.
Tại sao cần kế thừa?
Giả sử bạn cần viết một đoạn mã, và bạn quyết định làm điều đó dưới dạng một lớp. Sau đó, bạn phát hiện rằng trong dự án của bạn đã có một lớp làm gần như tất cả những gì bạn cần trong lớp của mình. Bạn có thể đơn giản sao chép mã của lớp đó vào lớp của mình và thoải mái sử dụng.
Hoặc bạn có thể "giống như sao chép". Bạn có thể tuyên bố lớp đó là cha của lớp mình, và sau đó Python sẽ thêm vào lớp của bạn hành vi của lớp cha.
Tưởng tượng bạn là thiên nhiên và muốn tạo ra một con Chó. Điều nào sẽ nhanh hơn—tạo chó từ vi khuẩn trong một tỷ năm hay thuần hóa sói trong 200 nghìn năm?
Ví dụ về kế thừa cơ bản
Giả sử bạn có một lớp cha là Animal
với thuộc tính name:
class Animal:
def __init__(self, name):
self.name = name
Chúng ta muốn tạo 2 lớp con cho nó — Dog
và Cat
, và thêm cho chúng phương thức speak
:
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
Trong ví dụ trên, các lớp con Dog
và Cat
kế thừa từ Animal
và thêm phương thức speak
.
Đối tượng lớp Dog
:
- Kế thừa thuộc tính
name
từAnimal
. - Thêm phương thức
speak
, trả về chuỗi đặc trưng cho chó.
Đối tượng lớp Cat
:
- Kế thừa thuộc tính
name
từAnimal
. - Thêm phương thức
speak
, trả về chuỗi đặc trưng cho mèo.
Phiên bản cuối cùng của mã trông như thế này:
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # Xuất: Buddy says Woof!
print(cat.speak()) # Xuất: Whiskers says Meow!
Trong ví dụ này, Animal
là lớp cha, còn Dog
và Cat
là các lớp con. Các lớp con kế thừa thuộc tính name
và phương thức __init__
từ lớp cha Animal
, nhưng thêm các phương thức speak
.
6.2 Bên dưới nắp ca-pô của kế thừa
Nếu bạn đã thêm cha cho lớp của mình, điều này rất giống như bạn đã sao chép mã của lớp cha vào lớp của mình.
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name):
super().__init__(name) # Gọi constructor của lớp cha
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def __init__(self, name):
super().__init__(name) # Gọi constructor của lớp cha
def speak(self):
return f"{self.name} says Meow!"
dog = Dog("Buddy")
cat = Cat("Whiskers")
print(dog.speak()) # Xuất: Buddy says Woof!
print(cat.speak()) # Xuất: Whiskers says Meow!
Đây không phải là mô tả chính xác, nhưng nếu bạn chưa từng đối mặt với khái niệm kế thừa, bạn có thể nghĩ về nó như vậy tạm thời. Sau này chúng ta sẽ thêm chi tiết vào đây.
6.3 Hệ thống phân cấp kế thừa
Rất thường xuyên, khi thiết kế mô hình phức tạp của một nhóm lớp lớn, bạn có thể gặp phải một hệ thống phân cấp kế thừa toàn bộ.
Ví dụ, bạn có một lớp Animal
— đó là lớp cơ bản cho tất cả động vật:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
Chúng ta thậm chí đã thêm cho nó phương thức speak
, nhưng vì động vật trừu tượng không nói, phương thức này chỉ ném ra ngoại lệ NotImplementedError
— đây là một thực tiễn tiêu chuẩn.
Sau đó, chúng ta thêm các lớp trung gian, tương ứng với các loại động vật: Mammal
— là động vật có vú và Bird
cho loài chim.
class Mammal(Animal):
def __init__(self, name, fur_color):
super().__init__(name) # Gọi constructor của lớp cha
self.fur_color = fur_color
class Bird(Animal):
def __init__(self, name, wing_span):
super().__init__(name) # Gọi constructor của lớp cha
self.wing_span = wing_span
def fly(self):
return f"{self.name} is flying with a wingspan of {self.wing_span} meters."
Và cuối cùng, chỉ ở giai đoạn cuối mới xuất hiện các lớp của loài động vật cụ thể:
class Dog(Mammal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Mammal):
def speak(self):
return f"{self.name} says Meow!"
class Parrot(Bird):
def speak(self):
return f"{self.name} says Squawk!"
Đây là cách mà mã cuối cùng hoạt động:
animals = [Dog("Buddy", "brown"), Cat("Whiskers", "white"), Parrot("Polly", 0.5)]
for animal in animals:
print(animal.speak())
print(f"{dog.name} has {dog.fur_color} fur.") # Xuất: Buddy has brown fur.
print(f"{cat.name} has {cat.fur_color} fur.") # Xuất: Whiskers has white fur.
print(parrot.fly()) # Xuất: Polly is flying with a wingspan of 0.5 meters.
Mặc dù về mặt kỹ thuật không có cấm tạo hệ thống phân cấp với hàng chục lớp cha, nhưng cần nhớ rằng nếu không cần thiết, tốt nhất là nên giữ mọi thứ đơn giản. Sự đơn giản là sức mạnh.
GO TO FULL VERSION