Lógica de validación
Parte de la sección Programación Orientada a Objetos del Journey de Lua de Coddy. Lección 47 de 70.
Hasta ahora, hemos explorado distintas formas de proteger los datos: las convenciones de nomenclatura indican la intención, las clausuras ocultan las variables por completo y las tablas de solo lectura impiden todas las modificaciones. Pero a menudo necesitas algo intermedio: permitir cambios, pero solo cambios válidos.
Aquí es donde los métodos setter se vuelven poderosos. En lugar de simplemente asignar un valor, un setter puede comprobar si el nuevo valor tiene sentido antes de aceptarlo:
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
endCuando alguien llama a person:setAge(-5), el método detecta la entrada no válida y se niega a actualizarla. El estado del objeto permanece coherente. Sin esta protección, los datos incorrectos podrían corromper silenciosamente tu programa: imagina calcular las prestaciones de jubilación con una edad negativa.
La validación puede ser tan simple o compleja como sea necesario. Puedes comprobar rangos, verificar tipos o asegurarte de que los valores coincidan con los formatos esperados. El principio clave es que el setter actúa como un guardián, asegurándose de que solo entren datos sensatos en tu objeto.
Desafío
Fácil¡Construyamos una clase Player que proteja sus atributos de salud y nivel mediante lógica de validación en los métodos setter! Esto garantiza que los personajes del juego nunca terminen con estadísticas imposibles.
Organizarás tu código en dos archivos:
Player.lua: crea una clase que administre las estadísticas de un jugador con la validación adecuada. El constructor:new(name)debe inicializar al jugador con un nombre,_healthestablecido en100y_levelestablecido en1. Incluye estos métodos::getName(): devuelve el nombre del jugador:getHealth(): devuelve la salud actual:getLevel(): devuelve el nivel actual:setHealth(value): actualiza la salud solo si el valor está entre 0 y 100 (inclusive). Si no es válido, muestraError: Health must be between 0 and 100y no cambia el valor.:setLevel(value): actualiza el nivel solo si el valor es 1 o mayor. Si no es válido, muestraError: Level must be at least 1y no cambia el valor.
main.lua: requiere tu módulo Player y lee un nombre de jugador, seguido de dos valores para probar los setters. Crea un jugador, intenta establecer su salud con el primer valor, intenta establecer su nivel con el segundo valor y, después, muestra las estadísticas finales del jugador.
Recibirás tres entradas:
- El nombre del jugador
- Un valor de salud que se intentará establecer (un número, que puede ser válido o no válido)
- Un valor de nivel que se intentará establecer (un número, que puede ser válido o no válido)
Tu salida debe mostrar cualquier mensaje de error de los intentos no válidos, seguido de las estadísticas finales del jugador:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Por ejemplo, si las entradas son Hero, -20 y 5, la salida debe ser:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5El setter de salud rechazó -20 (manteniendo la salud en 100), mientras que el setter de nivel aceptó 5 como válido.
Si las entradas son Warrior, 75 y 0, la salida debe ser:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Pruébalo tú mismo
-- Requiere el módulo Player
local Player = require('Player')
-- Lee las entradas
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: Crea un nuevo jugador con el nombre dado
-- TODO: Intenta establecer la salud del jugador a healthValue
-- TODO: Intenta establecer el nivel del jugador a levelValue
-- TODO: Imprime las estadísticas finales del jugador en el formato:
-- Nombre: {name}
-- Salud: {finalHealth}
-- Nivel: {finalLevel}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1El concepto de 'self'
Tablas con funciones'self' explícitoLa sintaxis de dos puntosPunto vs. dos puntosResumen - Punto en movimiento4Proyecto: Banco Digital
Configuración del proyectoMétodo de depósito2Patrón de prototipo de clase
El concepto de prototipoVinculación con __indexEl constructor :new()Inicialización de atributosInstancias independientesResumen - Fábrica de coches5Sobrecarga de operadores en POO
Sumar objetosRestar objetosConcatenar objetosComparar objetos (<, >)Resumen - Matemáticas de la billetera8Encapsulamiento
Convenciones de nomenclaturaClosures para privacidadAcceso mediante ClosuresTablas de solo lecturaLógica de validaciónResumen - Bóveda segura11Patrones de diseño (Lite)
Funciones FactoryTabla SingletonPatrón IteradorObserver (Listener)Resumen - Logger Factory3Estado y Comportamiento de los Objetos
Variables de InstanciaMétodos GetterMétodos SetterPropiedades CalculadasFormateo de StringsComprobaciones de IgualdadResumen - Calificación del Estudiante6Fundamentos de la herencia
Configuración de la herenciaHerencia de métodosExtender el constructorAñadir métodos hijosCompartido vs. ÚnicoResumen: Jerarquía de formasPractica por tu cuenta: Compilador de Lua online