验证逻辑
本课属于 Coddy Lua 学习旅程的“面向对象编程”单元。第 47 课,共 70 课。
到目前为止,我们探索了保护数据的不同方法:命名约定可以表明意图,闭包可以完全隐藏变量,而只读表可以阻止所有修改。但很多时候,你需要一种介于两者之间的方式:允许修改,但只允许进行有效的修改。
这就是 setter 方法发挥作用的地方。setter 不只是赋值,还可以在接受新值之前检查它是否合理:
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
end当有人调用 person:setAge(-5) 时,方法会捕获无效输入并拒绝更新。对象的状态保持一致。如果没有这种保护,错误数据可能会悄无声息地破坏你的程序:想象一下,用负数年龄计算退休福利。
验证可以根据需要设计得简单或复杂。你可以检查范围、验证类型,或确保值符合预期格式。关键原则是,设置方法充当把关者,确保只有合理的数据才能进入对象。
挑战
简单我们来编写一个 Player 类,通过 setter 方法中的验证逻辑保护角色的生命值和等级属性!这样可以确保游戏角色不会出现不可能的属性值。
你需要将代码分成两个文件:
Player.lua:创建一个类,用适当的验证逻辑管理玩家的属性。构造函数:new(name)应使用玩家姓名初始化玩家,将_health设为100,将_level设为1。包含以下方法::getName():返回玩家的姓名:getHealth():返回当前生命值:getLevel():返回当前等级:setHealth(value):仅当值在 0 到 100 之间(含 0 和 100)时更新生命值。如果值无效,则打印Error: Health must be between 0 and 100,并且不更改该值。:setLevel(value):仅当值大于或等于 1 时更新等级。如果值无效,则打印Error: Level must be at least 1,并且不更改该值。
main.lua:引入 Player 模块,读取玩家姓名,然后读取两个用于测试 setter 方法的值。创建一个玩家,尝试将生命值设为第一个值,再尝试将等级设为第二个值,然后打印玩家的最终属性。
你会收到三个输入:
- 玩家的姓名
- 尝试设置的生命值(一个数字,可能有效,也可能无效)
- 尝试设置的等级(一个数字,可能有效,也可能无效)
输出应显示无效设置操作产生的错误消息,然后显示玩家的最终属性:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}例如,如果输入是 Hero、-20 和 5,输出应为:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5生命值 setter 拒绝了 -20(生命值保持为 100),而等级 setter 接受了有效值 5。
如果输入是 Warrior、75 和 0,输出应为:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1亲手试试
-- 加载 Player 模块
local Player = require('Player')
-- 读取输入
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: 用给定的名字创建一个新玩家
-- TODO: 尝试将玩家的生命值设置为 healthValue
-- TODO: 尝试将玩家的等级设置为 levelValue
-- TODO: 按以下格式输出玩家的最终属性:
-- 姓名:{name}
-- 生命值:{finalHealth}
-- 等级:{finalLevel}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Lua 在线编译器