Logica di convalida
Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 47 di 70.
Finora abbiamo esplorato diversi modi per proteggere i dati: le convenzioni di denominazione segnalano l’intento, le chiusure nascondono completamente le variabili e le tabelle di sola lettura impediscono qualsiasi modifica. Ma spesso serve una via di mezzo: consentire le modifiche, ma solo quelle valide.
È qui che i metodi setter diventano potenti. Invece di limitarsi ad assegnare un valore, un setter può verificare se il nuovo valore è sensato prima di accettarlo:
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 qualcuno chiama person:setAge(-5), il metodo intercetta l'input non valido e rifiuta di aggiornare. Lo stato dell'oggetto rimane coerente. Senza questa protezione, dati errati potrebbero corrompere silenziosamente il tuo programma: immagina di calcolare i benefici pensionistici con un'età negativa.
La convalida può essere semplice o complessa, a seconda delle necessità. Potresti controllare gli intervalli, verificare i tipi o assicurarti che i valori corrispondano ai formati previsti. Il principio fondamentale è che il setter funge da guardiano, assicurandosi che nel tuo oggetto entrino solo dati sensati.
Sfida
FacileCreiamo una classe Player che protegga gli attributi health e level usando la logica di convalida nei metodi setter! In questo modo i personaggi del gioco non potranno mai ritrovarsi con statistiche impossibili.
Organizzerai il codice in due file:
Player.lua: crea una classe che gestisca le statistiche di un giocatore con una convalida appropriata. Il costruttore:new(name)dovrebbe inizializzare il giocatore con un nome,_healthimpostato a100e_levelimpostato a1. Includi questi metodi::getName(): restituisce il nome del giocatore:getHealth(): restituisce la salute attuale:getLevel(): restituisce il livello attuale:setHealth(value): aggiorna la salute solo se il valore è compreso tra 0 e 100 (inclusi). Se non è valido, stampaError: Health must be between 0 and 100e non modificare il valore.:setLevel(value): aggiorna il livello solo se il valore è pari o superiore a 1. Se non è valido, stampaError: Level must be at least 1e non modificare il valore.
main.lua: importa il modulo Player e leggi il nome di un giocatore, poi due valori per provare i setter. Crea un giocatore, prova a impostare la sua salute al primo valore, prova a impostare il suo livello al secondo valore, quindi stampa le statistiche finali del giocatore.
Riceverai tre input:
- Il nome del giocatore
- Un valore di salute da provare a impostare (un numero, che può essere valido o non valido)
- Un valore di livello da provare a impostare (un numero, che può essere valido o non valido)
L'output dovrebbe mostrare eventuali messaggi di errore relativi ai tentativi non validi, seguiti dalle statistiche finali del giocatore:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Per esempio, se gli input sono Hero, -20 e 5, l'output dovrebbe essere:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5Il setter della salute ha rifiutato -20 (mantenendo la salute a 100), mentre il setter del livello ha accettato 5 come valore valido.
Se gli input sono Warrior, 75 e 0, l'output dovrebbe essere:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Provalo tu
-- Importa il modulo Player
local Player = require('Player')
-- Leggi gli input
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: Crea un nuovo giocatore con il nome fornito
-- TODO: Prova a impostare la salute del giocatore su healthValue
-- TODO: Prova a impostare il livello del giocatore su levelValue
-- TODO: Stampa le statistiche finali del giocatore nel formato:
-- Name: {name}
-- Health: {finalHealth}
-- Level: {finalLevel}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Il concetto di «self»
Tabelle con funzioni«self» esplicitoLa sintassi dei due puntiPunto o due puntiRiepilogo - Spostare il punto4Progetto: Banca digitale
Configurazione del progettoMetodo di deposito2Schema del prototipo di classe
Il concetto di prototipoCollegare con __indexIl costruttore :new()Inizializzare gli attributiIstanze indipendentiRiepilogo - Fabbrica di auto5Sovraccarico degli operatori nella OOP
Sommare oggettiSottrarre oggettiConcatenare oggettiConfrontare oggetti (<, >)Ripasso - Calcoli con il portafoglio8Incapsulamento
Convenzioni di denominazioneClosure per la privacyAccesso tramite closureTabelle di sola letturaLogica di convalidaRiepilogo - Cassaforte sicura11Modelli di progettazione (base)
Funzioni factoryTabella singletonPattern IteratorObserver (listener)Riepilogo - Factory per logger3Stato e comportamento degli oggetti
Variabili di istanzaMetodi getterMetodi setterProprietà calcolateFormattazione delle stringheControlli di uguaglianzaRiepilogo - Voto dello studente6Fondamenti dell'ereditarietà
Configurare l'ereditarietàEreditare i metodiEstendere il costruttoreAggiungere metodi alla classe figliaCondiviso vs specificoRiepilogo - Gerarchia delle formeEsercitati da solo: Compilatore Lua online