Logic kiểm tra hợp lệ
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 47 trên 70.
Đến nay, chúng ta đã khám phá nhiều cách bảo vệ dữ liệu: quy ước đặt tên thể hiện mục đích, closure ẩn hoàn toàn các biến, còn bảng chỉ đọc ngăn mọi thay đổi. Nhưng thường thì bạn cần một giải pháp ở giữa: cho phép thay đổi, nhưng chỉ những thay đổi hợp lệ.
Đây là lúc các phương thức setter phát huy tác dụng. Thay vì chỉ gán một giá trị, phương thức setter có thể kiểm tra xem giá trị mới có hợp lý không trước khi chấp nhận:
local Person = {}
Person.__index = Person
function Person:new(name, age)
local obj = {
_name = name,
_age = age
}
setmetatable(obj, Person)
return obj
end
function Person:setAge(newAge)
if newAge < 0 then
print("Error: Age cannot be negative")
return
end
self._age = newAge
endKhi ai đó gọi person:setAge(-5), phương thức phát hiện đầu vào không hợp lệ và từ chối cập nhật. Trạng thái của đối tượng vẫn nhất quán. Nếu không có biện pháp bảo vệ này, dữ liệu xấu có thể âm thầm làm hỏng chương trình của bạn: hãy tưởng tượng bạn tính trợ cấp hưu trí với số tuổi âm.
Việc kiểm tra tính hợp lệ có thể đơn giản hoặc phức tạp tùy nhu cầu. Bạn có thể kiểm tra phạm vi, xác minh kiểu dữ liệu hoặc đảm bảo các giá trị khớp với định dạng mong đợi. Nguyên tắc cốt lõi là phương thức setter đóng vai trò như người gác cổng, đảm bảo chỉ dữ liệu hợp lý mới được đưa vào đối tượng của bạn.
Thử thách
DễHãy tạo một lớp Player để bảo vệ các thuộc tính sức khỏe và cấp độ bằng logic xác thực trong các phương thức setter! Nhờ vậy, chỉ số của nhân vật trong trò chơi sẽ không bao giờ rơi vào trạng thái bất khả thi.
Bạn sẽ tổ chức code trong hai tệp:
Player.lua: Tạo một lớp quản lý chỉ số của người chơi với bước xác thực phù hợp. Hàm khởi tạo:new(name)sẽ tạo người chơi với tên, đặt_healththành100và_levelthành1. Thêm các phương thức sau::getName(): trả về tên người chơi:getHealth(): trả về sức khỏe hiện tại:getLevel(): trả về cấp độ hiện tại:setHealth(value): chỉ cập nhật sức khỏe nếu giá trị nằm trong khoảng từ 0 đến 100, bao gồm cả hai đầu. Nếu giá trị không hợp lệ, in raError: Health must be between 0 and 100và không thay đổi giá trị.:setLevel(value): chỉ cập nhật cấp độ nếu giá trị từ 1 trở lên. Nếu giá trị không hợp lệ, in raError: Level must be at least 1và không thay đổi giá trị.
main.lua: Yêu cầu module Player và đọc tên người chơi, sau đó đọc hai giá trị để kiểm tra các setter. Tạo người chơi, thử đặt sức khỏe thành giá trị thứ nhất, thử đặt cấp độ thành giá trị thứ hai, rồi in ra các chỉ số cuối cùng của người chơi.
Bạn sẽ nhận ba đầu vào:
- Tên người chơi
- Giá trị sức khỏe cần thử đặt, là một số và có thể hợp lệ hoặc không hợp lệ
- Giá trị cấp độ cần thử đặt, là một số và có thể hợp lệ hoặc không hợp lệ
Đầu ra cần hiển thị mọi thông báo lỗi do các lần thử không hợp lệ, sau đó là các chỉ số cuối cùng của người chơi:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Ví dụ, nếu đầu vào là Hero, -20 và 5, đầu ra sẽ là:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5Setter sức khỏe từ chối -20 (giữ sức khỏe ở mức 100), còn setter cấp độ chấp nhận 5 là hợp lệ.
Nếu đầu vào là Warrior, 75 và 0, đầu ra sẽ là:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Tự làm thử
-- Nạp module Player
local Player = require('Player')
-- Đọc dữ liệu đầu vào
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: Tạo người chơi mới với tên đã cho
-- TODO: Thử đặt sức khỏe của người chơi thành healthValue
-- TODO: Thử đặt cấp độ của người chơi thành levelValue
-- TODO: In ra chỉ số cuối cùng của người chơi theo định dạng:
-- Tên: {name}
-- Sức khỏe: {finalHealth}
-- Cấp độ: {finalLevel}
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