Lógica de Validação
Parte da seção Object Oriented Programming do Journey de Lua da Coddy — lição 47 de 70.
Até agora, exploramos diferentes maneiras de proteger dados — convenções de nomenclatura sinalizam intenção, closures escondem variáveis completamente e tabelas somente leitura impedem todas as modificações. Mas muitas vezes você precisa de algo intermediário: permitir alterações, mas apenas as válidas.
É aqui que os métodos setter se tornam poderosos. Em vez de apenas atribuir um valor, um setter pode verificar se o novo valor faz sentido antes de aceitá-lo:
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
endQuando alguém chama person:setAge(-5), o método captura a entrada inválida e se recusa a atualizar. O estado do objeto permanece consistente. Sem essa proteção, dados incorretos poderiam corromper silenciosamente seu programa — imagine calcular benefícios de aposentadoria com uma idade negativa.
A validação pode ser tão simples ou complexa quanto necessário. Você pode verificar intervalos, validar tipos ou garantir que os valores correspondam aos formatos esperados. O princípio fundamental é que o setter atua como um guardião, garantindo que apenas dados sensatos entrem em seu objeto.
Desafio
FácilVamos construir uma classe Player que protege seus atributos de vida e nível usando lógica de validação em métodos setter! Isso garante que os personagens do jogo nunca terminem com estatísticas impossíveis.
Você organizará seu código em dois arquivos:
Player.lua: Crie uma classe que gerencie as estatísticas de um jogador com a validação adequada. O construtor:new(name)deve inicializar o jogador com um nome,_healthdefinido como100e_leveldefinido como1. Inclua estes métodos::getName()— retorna o nome do jogador:getHealth()— retorna a vida atual:getLevel()— retorna o nível atual:setHealth(value)— atualiza a vida apenas se o valor estiver entre 0 e 100 (inclusive). Se for inválido, imprimaError: Health must be between 0 and 100e não altere o valor.:setLevel(value)— atualiza o nível apenas se o valor for 1 ou maior. Se for inválido, imprimaError: Level must be at least 1e não altere o valor.
main.lua: Requeira seu módulo Player e leia o nome de um jogador, depois dois valores para testar os setters. Crie um jogador, tente definir sua vida para o primeiro valor, tente definir seu nível para o segundo valor e, em seguida, imprima as estatísticas finais do jogador.
Você receberá três entradas:
- O nome do jogador
- Um valor de vida para tentar definir (um número, pode ser válido ou inválido)
- Um valor de nível para tentar definir (um número, pode ser válido ou inválido)
Sua saída deve mostrar quaisquer mensagens de erro de tentativas inválidas, seguidas pelas estatísticas finais do jogador:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Por exemplo, se as entradas forem Hero, -20 e 5, a saída deve ser:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5O setter de vida rejeitou -20 (mantendo a vida em 100), enquanto o setter de nível aceitou 5 como válido.
Se as entradas forem Warrior, 75 e 0, a saída deve ser:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Folha de consulta
Os métodos setter permitem que você valide dados antes de atualizar as propriedades do objeto, garantindo que apenas valores válidos sejam aceitos.
Um setter básico com validação:
function Person:setAge(newAge)
if newAge < 0 then
print("Error: Age cannot be negative")
return
end
self._age = newAge
endO setter atua como um guardião — ele verifica se o novo valor é válido antes de atualizar a propriedade interna. Se a validação falhar, ele imprime um erro e retorna antecipadamente sem modificar os dados.
A validação pode incluir:
- Verificações de intervalo (ex: age >= 0)
- Limites de fronteira (ex: 0 <= health <= 100)
- Verificação de tipo
- Validação de formato
Isso evita que dados inválidos corrompam o estado do seu objeto e mantém seu programa consistente.
Experimente você mesmo
-- Requer o módulo Player
local Player = require('Player')
-- Lê as entradas
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: Criar um novo jogador com o nome fornecido
-- TODO: Tentar definir a vida do jogador para healthValue
-- TODO: Tentar definir o nível do jogador para levelValue
-- TODO: Imprimir as estatísticas finais do jogador no formato:
-- Nome: {name}
-- Vida: {finalHealth}
-- Nível: {finalLevel}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
1O Conceito 'Self'
Tabelas com Funções'self' ExplícitoA Sintaxe de Dois-pontosPonto vs Dois-pontosRecapitulação - Movendo o Ponto4Projeto: Banco Digital
Configuração do ProjetoMétodo de Depósito7Polimorfismo e Sobrescrita
Sobrescrita de MétodosChamando Métodos da Classe PaiDuck TypingInterface ComumVerificando o TipoRecapitulação - Papéis de Funcionários10Projeto: Gerenciador de Formas
Configuração do ProjetoClasse Retângulo2Padrão de Protótipo de Classe
O Conceito de ProtótipoVinculando com __indexO Construtor :new()Inicializando AtributosInstâncias IndependentesRecapitulação - Fábrica de Carros5Sobrecarga de Operadores em POO
Somando ObjetosSubtraindo ObjetosConcatenando ObjetosComparando Objetos (<, >)Recapitulação - Matemática de Carteira8Encapsulamento
Convenções de NomenclaturaClosures para PrivacidadeAcesso via ClosuresTabelas Somente LeituraLógica de ValidaçãoRecapitulação - Cofre Seguro11Padrões de Projeto (Lite)
Funções FactoryTabela SingletonPadrão IteratorObserver (Listener)Recapitulação - Logger Factory3Estado e Comportamento do Objeto
Variáveis de InstânciaMétodos GetterMétodos SetterPropriedades CalculadasFormatação de StringsVerificações de IgualdadeRecapitulação - Nota do Aluno6Fundamentos de Herança
Configurando a HerançaHerdando MétodosEstendendo o ConstrutorAdicionando Métodos FilhosCompartilhado vs ÚnicoRecapitulação - Hierarquia de Formas