Menu
CoddyTech

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")
end

Dò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ôi

Mẫ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.

challenge icon

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ằng Person.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 politely

Ví 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
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch Lua online