Mẫu Iterator
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 64 trên 70.
Khi lưu một tập hợp các mục bên trong một đối tượng, bạn thường muốn lặp qua chúng. Vòng lặp for tổng quát của Lua hoạt động với mọi hàm lặp: vòng lặp gọi hàm trước mỗi lần lặp và dừng khi hàm trả về nil.
Mẫu Iterator cung cấp cho đối tượng một phương thức trả về một hàm như vậy. Hàm giữ vị trí của mình trong một biến cục bộ, nên vị trí đó thuộc về một vòng lặp, chứ không phải tập hợp:
local Collection = {}
Collection.__index = Collection
function Collection:new()
local obj = { items = {} }
setmetatable(obj, Collection)
return obj
end
function Collection:add(item)
table.insert(self.items, item)
end
function Collection:iter()
local index = 0
return function()
index = index + 1
return self.items[index]
end
endMỗi lần gọi bag:iter() sẽ tạo một hàm mới có index riêng, bắt đầu từ 0. Hàm này là một bao đóng: nó vẫn có thể dùng index và self sau khi iter trả về. Sau phần tử cuối cùng, self.items[index] là nil, và vòng lặp dừng lại:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag:iter() do
print(item) -- apple, rồi đến banana
end
for item in bag:iter() do
print(item) -- lại là apple, rồi đến banana
endHãy giữ vị trí bên ngoài chính tập hợp. Nếu đối tượng lưu self.index và tự làm trình lặp, vòng lặp đầu tiên sẽ để chỉ số ở cuối, nên vòng lặp thứ hai sẽ không in ra gì. Nếu một vòng lặp dừng sớm bằng break, vòng lặp tiếp theo sẽ bắt đầu từ giữa.
Thử thách
DễHãy tạo một lớp Playlist để bạn có thể lặp qua bằng vòng lặp for tổng quát của Lua! Bạn sẽ triển khai mẫu Iterator bằng phương thức :iter(), phương thức này trả về một hàm lặp.
Bạn sẽ sắp xếp code trong hai tệp:
Playlist.lua: Tạo một lớp Playlist lưu trữ các bài hát. Lớp của bạn cần một hàm khởi tạo:new()để khởi tạo danh sách bài hát trống và một phương thức:addSong(title)để thêm bài hát vào danh sách. Quan trọng nhất, hãy thêm phương thức:iter()trả về một hàm mới mỗi khi được gọi. Hàm đó lưu vị trí của mình trong một biến cục bộ và trả về bài hát tiếp theo mỗi khi được gọi, hoặcnilkhi không còn bài hát nào.main.lua: Yêu cầu module Playlist và tạo một danh sách phát mới. Thêm bài hát vào danh sách dựa trên các đầu vào bạn nhận được, sau đó dùng vòng lặpfortổng quát vớiplaylist:iter()để in tiêu đề mỗi bài hát trên một dòng riêng.
Vì mỗi lần gọi :iter() đều bắt đầu từ bài hát đầu tiên, bạn có thể lặp qua cùng một danh sách phát bao nhiêu lần tùy ý.
Bạn sẽ nhận được ba đầu vào, mỗi đầu vào là tiêu đề một bài hát cần thêm vào danh sách phát, theo thứ tự.
Ví dụ, nếu các đầu vào là Bohemian Rhapsody, Stairway to Heaven và Hotel California, đầu ra sẽ là:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaNếu các đầu vào là Yesterday, Imagine và Let It Be, đầu ra sẽ là:
Yesterday
Imagine
Let It BeTự làm thử
-- Nạp module Playlist bằng require
local Playlist = require('Playlist')
-- Đọc tên của ba bài hát từ đầu vào
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Tạo một danh sách phát mới bằng Playlist:new()
-- TODO: Thêm ba bài hát vào danh sách phát bằng :addSong()
-- TODO: Dùng vòng lặp for tổng quát với playlist:iter()
-- và in tên mỗi bài hát trên một dòng riêng
-- Gợi ý: for song in playlist:iter() do ... end
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ề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