Menu
Coddy logo textTech

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
end

Quando 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.

challenge icon

Desafio

Fácil

Vamos 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, _health definido como 100 e _level definido como 1. 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, imprima Error: Health must be between 0 and 100 e não altere o valor.
    • :setLevel(value) — atualiza o nível apenas se o valor for 1 ou maior. Se for inválido, imprima Error: Level must be at least 1 e 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:

  1. O nome do jogador
  2. Um valor de vida para tentar definir (um número, pode ser válido ou inválido)
  3. 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: 5

O 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: 1

Folha 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
end

O 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}
quiz iconTeste seus conhecimentos

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