Gọi phương thức của lớp cha
Thuộc phần Lập trình hướng đối tượng trong hành trình Lua của Coddy. Bài học 38 trên 70.
Đôi khi, bạn không muốn ghi đè hoàn toàn một phương thức. Thay vào đó, bạn có thể muốn mở rộng hành vi của lớp cha: thực hiện những gì lớp cha làm, rồi thêm điều gì đó. Để làm vậy, bạn có thể gọi trực tiếp phương thức của lớp cha bên trong phương thức ghi đè của lớp con.
Kỹ thuật này dùng cú pháp dấu chấm với tên lớp cha, đồng thời truyền rõ self làm đối số đầu tiên:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog mở rộng hành vi của lớp cha
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
Animal.speak(self) -- Gọi phương thức (method) của lớp cha trước
print(self.name .. " wags tail happily")
endDòng then chốt là Animal.speak(self). Bằng cách dùng cú pháp dấu chấm với lớp cha và truyền self theo cách thủ công, ta gọi phương thức gốc trước khi thêm hành vi riêng:
local buddy = Dog:new("Buddy")
buddy:speak()
-- Đầu ra:
-- Buddy phát ra âm thanh
-- Buddy vui vẻ vẫy đuôiMẫu này hữu ích khi phương thức của lớp cha thực hiện công việc quan trọng mà bạn không muốn lặp lại. Lớp con có thể chạy logic của lớp cha trước, sau hoặc ngay giữa phần code của mình, giúp bạn kiểm soát hoàn toàn cách kết hợp các hành vi.
Thử thách
DễHãy xây dựng một hệ thống chào hỏi, trong đó FormalPerson mở rộng hành vi của một Person thông thường! Thay vì thay thế hoàn toàn cách một người tự giới thiệu, phiên bản trang trọng sẽ giới thiệu theo cách thông thường trước, sau đó thêm một nét lịch sự.
Bạn sẽ sắp xếp code trong ba tệp:
Person.lua: Lớp cơ sở với hàm khởi tạo:new(name)lưu tên người đó. Thêm phương thức:introduce()để in tên người đó, theo sau làsays hi. Đây là hành vi cơ sở sẽ được mở rộng.FormalPerson.lua: Lớp con kế thừa từ Person. Hàm khởi tạo nên gọi hàm khởi tạo của lớp cha để xử lý tên. Ghi đè phương thức:introduce(), nhưng thay vì thay thế hoàn toàn hành vi của lớp cha, hãy gọi phương thức của lớp cha trước bằngPerson.introduce(self), rồi in thêm một dòng có tên người đó, theo sau làbows politely.main.lua: Nạp module FormalPerson, đọc tên từ đầu vào, tạo một instance FormalPerson và gọi:introduce()để xem cả hai hành vi được kết hợp.
Bạn sẽ nhận một đầu vào: tên người đó.
Khi gọi :introduce() trên một FormalPerson, chương trình sẽ tạo ra hai dòng đầu ra: dòng đầu tiên từ phương thức của lớp cha, dòng thứ hai từ phần bổ sung của lớp con:
{name} says hi
{name} bows politelyVí dụ, nếu đầu vào là Eleanor, đầu ra sẽ là:
Eleanor says hi
Eleanor bows politelyĐiểm mấu chốt ở đây là FormalPerson không sao chép logic "says hi". Lớp này giao phần việc đó cho phương thức của lớp cha, rồi bổ sung hành vi riêng của mình. Cách này giúp code gọn gàng và cho thấy lớp con có thể mở rộng chức năng của lớp cha thay vì thay thế nó!
Tự làm thử
-- main.lua: Điểm khởi đầu của hệ thống chào hỏi
local FormalPerson = require('FormalPerson')
-- Đọc tên người dùng từ đầu vào
local name = io.read()
-- TODO: Tạo một instance FormalPerson với tên đã cho
-- TODO: Gọi phương thức introduce trên instance FormalPerson
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Khái niệm “self”
Bảng với hàm“self” tường minhCú pháp dấu hai chấmDấu chấm và dấu hai chấmÔn tập: Điểm chuyển động4Dự án: Ngân hàng số
Thiết lập dự ánPhương thức nạp tiền7Đa hình và ghi đè
Ghi đè phương thứcGọi phương thức của lớp chaGõ kiểu vịtGiao diện chungKiểm tra kiểuÔn tập: Vai trò của nhân viên2Mẫu Prototype cho lớp
Khái niệm PrototypeLiên kết bằng __indexHàm khởi tạo :new()Khởi tạo thuộc tínhCác instance độc lậpÔn tập: Nhà máy ô tô5Nạp chồng toán tử trong OOP
Cộng các đối tượngTrừ các đối tượngNối các đối tượngSo sánh các đối tượng (<, >)Ôn tập: phép tính với ví tiền8Đóng gói
Quy ước đặt tênClosure để bảo mậtTruy cập qua closureBảng chỉ đọcLogic kiểm tra hợp lệTổng kết: Két an toàn11Mẫu thiết kế (cơ bản)
Hàm tạo đối tượngBảng SingletonMẫu IteratorObserver (Listener)Ôn tập: Factory Logger3Trạng thái và hành vi của đối tượng
Biến instancePhương thức getterPhương thức setterThuộc tính tính toánĐịnh dạng chuỗiKiểm tra tính bằng nhauÔn tập: điểm số học sinh6Cơ bản về kế thừa
Thiết lập kế thừaKế thừa phương thứcMở rộng hàm khởi tạoThêm phương thức cho lớp conDùng chung và riêngÔn tập: hệ phân cấp hình dạngTự luyện tập: Trình biên dịch Lua online