Menu
CoddyTech

Ủy quyền

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 50 trên 70.

Lưu một đối tượng bên trong một đối tượng khác mới chỉ là bước đầu tiên. Sức mạnh thực sự của phép hợp thành đến từ ủy quyền, khi đối tượng bên ngoài chuyển tiếp các lời gọi phương thức đến những thành phần bên trong.

Hãy nghĩ về việc khởi động một chiếc xe. Bạn không mở nắp ca-pô rồi tự tay quay động cơ. Thay vào đó, bạn vặn chìa khóa, rồi xe tự xử lý phần còn lại.

Trong code, điều này có nghĩa là lớp Car cung cấp một phương thức :start() đơn giản, giao phần việc thực sự cho động cơ:

function Car:start()
    print("Turning the key...")
    self.engine:run()  -- Giao việc cho đối tượng (object) bên trong
end

Chiếc xe không cần biết động cơ hoạt động như thế nào. Nó chỉ yêu cầu động cơ thực hiện nhiệm vụ của mình. Nhờ vậy, trách nhiệm được tách biệt. Lớp Engine xử lý logic của động cơ, còn Car điều phối các bộ phận:

function Engine:run()
    print("Engine running at " .. self.horsepower .. " HP")
end

local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- Đầu ra:
-- Đang vặn chìa khóa...
-- Engine đang chạy ở mức 250 HP

Ủy quyền tạo ra một giao diện rõ ràng cho người dùng lớp của bạn. Họ tương tác với chiếc xe, không phải các bộ phận bên trong. Nếu sau này bạn thay bằng một cách triển khai động cơ khác, giao diện công khai của chiếc xe vẫn giữ nguyên: chỉ phần ủy quyền bên trong thay đổi.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống trình phát nhạc minh họa cách ủy quyền! Bạn sẽ tạo một thành phần Speaker và một MusicPlayer chứa thành phần đó. Trình phát không trực tiếp xử lý việc phát âm thanh mà ủy quyền trách nhiệm đó cho loa bên trong.

Bạn sẽ sắp xếp code trong ba tệp:

  • Speaker.lua: Tạo một lớp Speaker với hàm khởi tạo :new(volume) để lưu mức âm lượng. Thêm phương thức :playSound(trackName) để in ra: Playing "{trackName}" at volume {volume}
  • MusicPlayer.lua: Tạo một lớp MusicPlayer có hàm khởi tạo :new(brand, speaker) nhận tên thương hiệu và một đối tượng Speaker. Trình phát lưu loa bên trong nó. Thêm các phương thức sau:
    • :play(trackName): in ra {brand} player starting..., sau đó ủy quyền cho phương thức :playSound() của loa
    • :stop(): in ra {brand} player stopped
  • main.lua: Kết hợp mọi thứ lại với nhau! Đọc đầu vào cho mức âm lượng của loa, thương hiệu trình phát và tên bài nhạc. Tạo Speaker trước, rồi truyền nó vào hàm khởi tạo của MusicPlayer. Gọi phương thức :play() của trình phát với tên bài nhạc, sau đó gọi :stop().

Bạn sẽ nhận ba đầu vào:

  1. Mức âm lượng của loa (một số)
  2. Thương hiệu của trình phát nhạc (một chuỗi)
  3. Tên bài nhạc cần phát (một chuỗi)

Đầu ra cần thể hiện trình phát phối hợp với loa:

{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stopped

Ví dụ, nếu đầu vào là 75, SoundMax và Summer Vibes, đầu ra sẽ là:

SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stopped

Lưu ý rằng MusicPlayer không biết cách phát âm thanh. Nó chỉ yêu cầu loa xử lý phần đó. Đây là cách hoạt động của việc ủy quyền: đối tượng bên ngoài cung cấp một giao diện rõ ràng, còn thành phần bên trong thực hiện công việc chuyên biệt!

Tự làm thử

-- main.lua
-- Kết hợp mọi thứ lại!

local Speaker = require('Speaker')
local MusicPlayer = require('MusicPlayer')

-- Đọc đầu vào
local volume = tonumber(io.read())
local brand = io.read()
local trackName = io.read()

-- TODO: Tạo một Speaker với âm lượng đã cho

-- TODO: Tạo một MusicPlayer với thương hiệu và loa

-- TODO: Gọi phương thức play của MusicPlayer với tên bài hát

-- TODO: Gọi phương thức stop của MusicPlayer
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