Kiểm tra tính bằng nhau
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 17 trên 70.
Bạn đã thấy __tostring điều khiển cách một đối tượng hiển thị. Một metamethod hữu ích khác là __eq, dùng để xác định khi nào hai đối tượng được xem là bằng nhau khi dùng toán tử ==.
Theo mặc định, khi so sánh hai bảng bằng ==, chương trình kiểm tra xem chúng có phải là cùng một bảng trong bộ nhớ hay không. Hai đối tượng riêng biệt có dữ liệu giống hệt nhau sẽ trả về false:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Đầu ra: false (các bảng khác nhau)Với __eq, bạn có thể định nghĩa logic so sánh bằng của riêng mình. Trong một lớp, bạn thêm nó giống như __tostring, dưới dạng một hàm trong bảng lớp. Để phép so sánh bằng hoạt động, cả hai đối tượng phải dùng chung metatable:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endGiờ đây, hai đối tượng User được xem là bằng nhau nếu chúng có cùng ID, bất kể các trường khác:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Đầu ra: true (cùng ID)
print(u1 == u3) -- Đầu ra: false (ID khác nhau)Mẫu này hữu ích khi các đối tượng đại diện cho những thực thể trong thế giới thực có mã định danh duy nhất: chẳng hạn như khi so sánh các bản ghi trong cơ sở dữ liệu, thực thể trong trò chơi hoặc bất kỳ đối tượng nào mà danh tính quan trọng hơn vị trí trong bộ nhớ.
Thử thách
DễHãy tạo một lớp Product có thể xác định hai sản phẩm có phải là cùng một mặt hàng hay không, ngay cả khi chúng được lưu trong các bảng hoàn toàn khác nhau! Trong các hệ thống bán lẻ, sản phẩm thường có mã SKU (Stock Keeping Units) duy nhất, và hai sản phẩm được xem là bằng nhau nếu có cùng SKU, bất kể các chi tiết khác như giá có thay đổi hay không.
Bạn sẽ tổ chức code trong hai tệp:
Product.lua: Định nghĩa lớpProducttheo mẫu prototype tiêu chuẩn. Mỗi sản phẩm cần lưusku(mã định danh duy nhất) vàname. Triển khai phương thức metamethod__eqđể hai sản phẩm được xem là bằng nhau khi chúng có cùng SKU: tên không ảnh hưởng đến việc so sánh bằng.main.lua: Yêu cầu module Product và tạo một số instance sản phẩm. So sánh chúng bằng toán tử==để xem logic so sánh bằng tùy chỉnh hoạt động.
Lớp Product cần có:
- Hàm khởi tạo
:new(sku, name) - Phương thức
:getInfo()trả về một chuỗi theo định dạng:[sku]: [name] - Phương thức metamethod
__eqso sánh sản phẩm dựa trên SKU
Bạn sẽ nhận được sáu đầu vào:
- SKU của sản phẩm thứ nhất
- Tên của sản phẩm thứ nhất
- SKU của sản phẩm thứ hai
- Tên của sản phẩm thứ hai
- SKU của sản phẩm thứ ba
- Tên của sản phẩm thứ ba
Trong tệp chính, hãy tạo ba sản phẩm bằng các đầu vào đã cho, sau đó in ra:
- Thông tin của từng sản phẩm (ba dòng)
- Kết quả so sánh sản phẩm 1 với sản phẩm 2
- Kết quả so sánh sản phẩm 1 với sản phẩm 3
Ví dụ, nếu các đầu vào là ABC123, Wireless Mouse, ABC123, Mouse (Updated), XYZ789 và Keyboard, đầu ra sẽ là:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
falseHãy chú ý rằng hai sản phẩm đầu tiên bằng nhau (cùng SKU), dù tên của chúng khác nhau. Đây chính là cách các hệ thống quản lý hàng tồn kho thực tế theo dõi sản phẩm khi tên thay đổi và được cập nhật!
Tự làm thử
-- Nạp module Product
local Product = require('Product')
-- Đọc dữ liệu đầu vào
local sku1 = io.read()
local name1 = io.read()
local sku2 = io.read()
local name2 = io.read()
local sku3 = io.read()
local name3 = io.read()
-- TODO: Tạo ba instance Product từ dữ liệu đầu vào
-- TODO: In ra thông tin của từng sản phẩm (ba dòng)
-- TODO: In ra kết quả so sánh sản phẩm 1 với sản phẩm 2
-- TODO: In ra kết quả so sánh sản phẩm 1 với sản phẩm 3
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