Trong lĩnh vực phát triển phần mềm, lập trình hướng đối tượng (OOP) nổi bật như một mô hình thiết yếu để tổ chức và quản lý các hệ thống code phức tạp, đồng thời phản ánh sát sao cách chúng ta mô hình hóa các vấn đề trong thế giới thực. Bài viết này đi sâu vào các khái niệm nền tảng của OOP bao gồm lớp, đối tượng, quy trình khởi tạo, kế thừa và đa hình, kèm theo các ví dụ code thực tế sử dụng ngôn ngữ Python.
Lớp và Đối tượng
Định nghĩa một Lớp
Trong OOP, một lớp đóng vai trò như một bản thiết kế (blueprint) để tạo ra các đối tượng có chung thuộc tính và hành vi. Trong Python, chúng ta sử dụng từ khóa class:
class Animal:
def __init__(self, ten, tuoi):
self.ten = ten
self.tuoi = tuoi
def chay(self):
print(f"{self.ten.upper()} đang chạy.")
def nghe_goi(self):
print(f"{self.ten.upper()} quay đầu lại!")
Đoạn code trên định nghĩa một lớp Animal với các thuộc tính ten và tuoi, cùng các phương thức chay() và nghe_goi(). Phương thức __init__() là một hàm đặc biệt dùng để khởi tạo các đối tượng mới.
Sử dụng Lớp – Khởi tạo Đối tượng
Sau khi định nghĩa lớp, chúng ta có thể tạo ra các đối tượng cụ thể thông qua tiến trình khởi tạo:
con_meo = Animal("Miu", 3)
print("Tên con vật là " + con_meo.ten.title())
print("Nó " + str(con_meo.tuoi) + " tuổi.")
Sau khi khởi tạo, chúng ta có thể truy cập vào các thuộc tính và phương thức của đối tượng bằng cú pháp dấu chấm:
con_meo.chay()
con_meo.nghe_goi()
Kế thừa và Đa hình
Kế thừa
Kế thừa là một tính năng mạnh mẽ trong OOP, cho phép tạo ra một lớp mới (lớp con) kế thừa toàn bộ thuộc tính và phương thức từ một lớp đã có (lớp cha), đồng thời có thể bổ sung hoặc ghi đè thành phần riêng.
class ThanhVienTruong:
so_luong = 0
def __init__(self, ten, tuoi, gioi_tinh):
self.ten = ten
self.tuoi = tuoi
self.gioi_tinh = gioi_tinh
self.dang_ky()
def dang_ky(self):
print(f"Đã đăng ký thành viên mới: [{self.ten}].")
ThanhVienTruong.so_luong += 1
def hien_thi(self):
print(f"----{self.ten}----")
for thuoc_tinh, gia_tri in self.__dict__.items():
print(thuoc_tinh, gia_tri)
print("----kết thúc----")
def __del__(self):
print(f"Hủy thành viên [{self.ten}]")
ThanhVienTruong.so_luong -= 1
class GiaoVien(ThanhVienTruong):
def __init__(self, ten, tuoi, gioi_tinh, luong, mon_hoc):
ThanhVienTruong.__init__(self, ten, tuoi, gioi_tinh)
self.luong = luong
self.mon_hoc = mon_hoc
def giang_day(self):
print(f"Giáo viên [{self.ten}] đang dạy môn [{self.mon_hoc}]")
class HocSinh(ThanhVienTruong):
def __init__(self, ten, tuoi, gioi_tinh, mon_hoc, hoc_phi):
ThanhVienTruong.__init__(self, ten, tuoi, gioi_tinh)
self.mon_hoc = mon_hoc
self.hoc_phi = hoc_phi
self.da_dong = 0
def dong_hoc_phi(self, so_tien):
print(f"Học sinh [{self.ten}] vừa đóng [{so_tien}]")
self.da_dong += so_tien
Nhờ kế thừa, cả hai lớp GiaoVien và HocSinh đều có sẵn các phương thức và thuộc tính của lớp cha ThanhVienTruong, đồng thời tự bổ sung thêm những thành phần đặc trưng.
Đa hình
Tính đa hình cho phép các đối tượng thuộc các lớp khác nhau phản hồi cùng một thông điệp (hay lời gọi phương thức) theo những cách riêng biệt. Trong Python, điều này được thể hiện qua việc nhiều lớp cùng triển khai một interface chung:
class DongVat:
def __init__(self, ten):
self.ten = ten
def keu(self):
pass
class Meo(DongVat):
def keu(self):
print(f"{self.ten}: Meo! Meo! Meo!")
class Cho(DongVat):
def keu(self):
print(f"{self.ten}: Gau! Gau! Gau!")
def goi_keu(doi_tuong):
doi_tuong.keu()
c1 = Meo("Tom")
d1 = Cho("Lucky")
goi_keu(c1) # Output: Tom: Meo! Meo! Meo!
goi_keu(d1) # Output: Lucky: Gau! Gau! Gau!
Trong ví dụ này, lớp DongVat có phương thức keu(), cả hai lớp Meo và Cho đều ghi đè (override) phương thức đó. Hàm goi_keu() minh họa cách cùng một lời gọi phương thức nhưng cho ra hành vi khác nhau tùy thuộc vào đối tượng được truyền vào.