Logika walidacji
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 47 z 70.
Do tej pory poznaliśmy różne sposoby ochrony danych: konwencje nazewnicze sygnalizują zamiar, domknięcia całkowicie ukrywają zmienne, a tabele tylko do odczytu uniemożliwiają wszelkie modyfikacje. Często jednak potrzebujesz czegoś pośredniego: możliwości wprowadzania zmian, ale tylko prawidłowych.
W tym miejscu metody ustawiające stają się potężne. Zamiast tylko przypisywać wartość, metoda ustawiająca może sprawdzić, czy nowa wartość ma sens, zanim ją zaakceptuje:
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
endGdy ktoś wywoła person:setAge(-5), metoda wykrywa nieprawidłowe dane wejściowe i odmawia aktualizacji. Stan obiektu pozostaje spójny. Bez tej ochrony błędne dane mogłyby po cichu uszkodzić program: wyobraź sobie obliczanie świadczeń emerytalnych dla osoby w ujemnym wieku.
Walidacja może być tak prosta lub złożona, jak to konieczne. Możesz sprawdzać zakresy, weryfikować typy lub upewniać się, że wartości odpowiadają oczekiwanym formatom. Kluczowa zasada jest taka, że setter pełni funkcję strażnika, dbając o to, by do obiektu trafiały tylko sensowne dane.
Wyzwanie
ŁatwyZbudujmy klasę Player, która chroni atrybuty zdrowia i poziomu za pomocą logiki walidacji w metodach ustawiających! Dzięki temu postacie w grze nigdy nie będą miały niemożliwych statystyk.
Podzielisz swój kod na dwa pliki:
Player.lua: Utwórz klasę, która zarządza statystykami gracza, stosując odpowiednią walidację. Konstruktor:new(name)powinien inicjalizować gracza z imieniem, ustawiając_healthna100i_levelna1. Dodaj następujące metody::getName(): zwraca imię gracza:getHealth(): zwraca aktualne zdrowie:getLevel(): zwraca aktualny poziom:setHealth(value): aktualizuje zdrowie tylko wtedy, gdy wartość mieści się w przedziale od 0 do 100 (włącznie). Jeśli jest nieprawidłowa, wyświetlError: Health must be between 0 and 100i nie zmieniaj wartości.:setLevel(value): aktualizuje poziom tylko wtedy, gdy wartość wynosi co najmniej 1. Jeśli jest nieprawidłowa, wyświetlError: Level must be at least 1i nie zmieniaj wartości.
main.lua: Załaduj moduł Player i odczytaj imię gracza, a następnie dwie wartości do przetestowania metod ustawiających. Utwórz gracza, spróbuj ustawić jego zdrowie na pierwszą wartość, spróbuj ustawić jego poziom na drugą wartość, a następnie wyświetl końcowe statystyki gracza.
Otrzymasz trzy dane wejściowe:
- Imię gracza
- Wartość zdrowia, którą chcesz ustawić (liczba, może być prawidłowa lub nieprawidłowa)
- Wartość poziomu, którą chcesz ustawić (liczba, może być prawidłowa lub nieprawidłowa)
Wynik powinien zawierać wszystkie komunikaty o błędach dotyczące nieprawidłowych prób, a następnie końcowe statystyki gracza:
Name: {name}
Health: {finalHealth}
Level: {finalLevel}Na przykład, jeśli dane wejściowe to Hero, -20 i 5, wynik powinien wyglądać następująco:
Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5Metoda ustawiająca zdrowie odrzuciła wartość -20 (pozostawiając zdrowie na poziomie 100), a metoda ustawiająca poziom zaakceptowała wartość 5 jako prawidłową.
Jeśli dane wejściowe to Warrior, 75 i 0, wynik powinien wyglądać następująco:
Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1Spróbuj swoich sił
-- Załaduj moduł Player
local Player = require('Player')
-- Odczytaj dane wejściowe
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())
-- TODO: Utwórz nowego gracza o podanym imieniu
-- TODO: Spróbuj ustawić zdrowie gracza na healthValue
-- TODO: Spróbuj ustawić poziom gracza na levelValue
-- TODO: Wyświetl końcowe statystyki gracza w formacie:
-- Imię: {name}
-- Zdrowie: {finalHealth}
-- Poziom: {finalLevel}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Koncepcja „self”
Tabele z funkcjamiJawne „self”Składnia z dwukropkiemKropka czy dwukropekPodsumowanie — poruszający się punkt4Projekt: Bank cyfrowy
Konfiguracja projektuMetoda wpłaty7Polimorfizm i nadpisywanie
Nadpisywanie metodWywoływanie metod klasy nadrzędnejTypowanie kaczeWspólny interfejsSprawdzanie typuPodsumowanie — role pracowników10Projekt: Menedżer kształtów
Konfiguracja projektuKlasa prostokątaKlasa kołaMetoda obwoduKolekcja kształtówPole całkowiteFiltrowanie kształtów2Wzorzec prototypu klasy
Koncepcja prototypuŁączenie za pomocą __indexKonstruktor :new()Inicjalizacja atrybutówNiezależne instancjePodsumowanie – fabryka samochodów5Przeciążanie operatorów w OOP
Dodawanie obiektówOdejmowanie obiektówŁączenie obiektówPorównywanie obiektów (<, >)Powtórka — działania na portfelu8Hermetyzacja
Konwencje nazewnictwaDomknięcia dla prywatnościDostęp za pomocą domknięćTabele tylko do odczytuLogika walidacjiPodsumowanie — bezpieczny sejf11Wzorce projektowe (podstawy)
Funkcje fabrykująceTabela SingletonWzorzec iteratoraObserwator (nasłuchujący)Powtórka — fabryka loggera3Stan i zachowanie obiektu
Zmienne instancjiMetody dostępoweMetody ustawiająceWłaściwości obliczaneFormatowanie ciągów znakówSprawdzanie równościPodsumowanie – ocena ucznia6Podstawy dziedziczenia
Konfiguracja dziedziczeniaDziedziczenie metodRozszerzanie konstruktoraDodawanie metod potomnychWspólne i unikalne elementyPowtórka — hierarchia kształtówPoćwicz samodzielnie: Kompilator Lua online