Lógica de Validação
Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy. Lição 47 de 70.
Até agora, exploramos diferentes maneiras de proteger dados: as convenções de nomenclatura sinalizam a intenção, os closures ocultam variáveis completamente e as 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, confirmar 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 coerentes entrem no seu objeto.
Desafio
FácilVamos criar uma classe Player que protege seus atributos de saúde e nível usando lógica de validação nos métodos setter! Isso garante que os personagens do jogo nunca terminem com atributos impossíveis.
Você organizará seu código em dois arquivos:
Player.lua: crie uma classe que gerencie os atributos de um jogador com 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 saúde atual:getLevel(): retorna o nível atual:setHealth(value): atualiza a saúde somente se o valor estiver entre 0 e 100 (inclusive). Se for inválido, exibaError: Health must be between 0 and 100e não altere o valor.:setLevel(value): atualiza o nível somente se o valor for 1 ou maior. Se for inválido, exibaError: Level must be at least 1e não altere o valor.
main.lua: exija seu módulo Player e leia um nome de jogador e, em seguida, dois valores para testar os setters. Crie um jogador, tente definir a saúde dele como o primeiro valor, tente definir o nível dele como o segundo valor e, depois, exiba os atributos finais do jogador.
Você receberá três entradas:
- O nome do jogador
- Um valor de saúde que será usado na tentativa de definição (um número, que pode ser válido ou inválido)
- Um valor de nível que será usado na tentativa de definição (um número, que pode ser válido ou inválido)
Sua saída deve exibir todas as mensagens de erro das tentativas inválidas, seguidas pelos atributos finais do jogador:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Por exemplo, se as entradas forem Hero, -20 e 5, a saída deverá ser:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5O setter de saúde rejeitou -20 (mantendo a saúde em 100), enquanto o setter de nível aceitou 5 como válido.
Se as entradas forem Warrior, 75 e 0, a saída deverá ser:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Experimente 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: Crie um novo jogador com o nome fornecido
-- TODO: Tente definir a saúde do jogador para healthValue
-- TODO: Tente definir o nível do jogador para levelValue
-- TODO: Imprima as estatísticas finais do jogador no formato:
-- Name: {name}
-- Health: {finalHealth}
-- Level: {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 Programação Orientada a Objetos
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ânguloClasse CírculoMétodo PerímetroColeção de FormasÁrea TotalFiltrar Formas2Padrã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 FormasPratique por conta própria: Compilador de Lua online