Menu
Coddy logo textTech

Логика валидации

Часть раздела Object Oriented Programming путешествия по Lua на Coddy — урок 47 из 70.

До сих пор мы рассматривали различные способы защиты данных: соглашения об именовании указывают на намерения, замыкания полностью скрывают переменные, а таблицы только для чтения предотвращают любые изменения. Но часто требуется нечто среднее: возможность вносить изменения, но только корректные.

Именно здесь методы-сеттеры становятся мощным инструментом. Вместо того чтобы просто присваивать значение, сеттер может проверить, имеет ли новое значение смысл, прежде чем принять его:

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

Когда кто-то вызывает person:setAge(-5), метод перехватывает некорректные входные данные и отказывается выполнять обновление. Состояние объекта остается согласованным. Без такой защиты некорректные данные могут незаметно нарушить работу вашей программы — представьте себе расчет пенсионных выплат при отрицательном возрасте.

Валидация может быть настолько простой или сложной, насколько это необходимо. Вы можете проверять диапазоны, верифицировать типы или гарантировать, что значения соответствуют ожидаемым форматам. Ключевой принцип заключается в том, что сеттер выступает в роли привратника, гарантируя, что в ваш объект попадают только корректные данные.

challenge icon

Задание

Легко

Давайте создадим класс Player, который защищает свои атрибуты здоровья и уровня с помощью логики валидации в методах-сеттерах! Это гарантирует, что игровые персонажи никогда не окажутся с невозможными характеристиками.

Вы организуете свой код в двух файлах:

  • Player.lua: Создайте класс, который управляет характеристиками игрока с надлежащей валидацией. Конструктор :new(name) должен инициализировать игрока с именем, _health установленным в 100, и _level установленным в 1. Включите следующие методы:
    • :getName() — возвращает имя игрока
    • :getHealth() — возвращает текущее здоровье
    • :getLevel() — возвращает текущий уровень
    • :setHealth(value) — обновляет здоровье только в том случае, если значение находится в диапазоне от 0 до 100 (включительно). Если значение неверно, выведите Error: Health must be between 0 and 100 и не изменяйте значение.
    • :setLevel(value) — обновляет уровень только в том случае, если значение равно 1 или больше. Если значение неверно, выведите Error: Level must be at least 1 и не изменяйте значение.
  • main.lua: Подключите ваш модуль Player и прочитайте имя игрока, а затем два значения для тестирования сеттеров. Создайте игрока, попытайтесь установить его здоровье в первое значение, попытайтесь установить его уровень во второе значение, а затем выведите итоговые характеристики игрока.

Вы получите три входных значения:

  1. Имя игрока
  2. Значение здоровья для попытки установки (число, может быть валидным или невалидным)
  3. Значение уровня для попытки установки (число, может быть валидным или невалидным)

Ваш вывод должен содержать любые сообщения об ошибках от невалидных попыток, за которыми следуют итоговые характеристики игрока:

Name: {name}
Health: {finalHealth}
Level: {finalLevel}

Например, если входные данные — Hero, -20 и 5, вывод должен быть следующим:

Error: Health must be between 0 and 100
Name: Hero
Health: 100
Level: 5

Сеттер здоровья отклонил -20 (сохранив здоровье на уровне 100), в то время как сеттер уровня принял 5 как валидное значение.

Если входные данные — Warrior, 75 и 0, вывод должен быть следующим:

Error: Level must be at least 1
Name: Warrior
Health: 75
Level: 1

Шпаргалка

Методы-сеттеры позволяют проверять данные перед обновлением свойств объекта, гарантируя, что будут приняты только допустимые значения.

Базовый сеттер с валидацией:

function Person:setAge(newAge)
    if newAge < 0 then
        print("Error: Age cannot be negative")
        return
    end
    self._age = newAge
end

Сеттер выступает в роли «привратника» — он проверяет, является ли новое значение допустимым, прежде чем обновлять внутреннее свойство. Если валидация не проходит, он выводит ошибку и завершает выполнение раньше, не изменяя данные.

Валидация может включать:

  • Проверка диапазона (например, age >= 0)
  • Граничные ограничения (например, 0 <= health <= 100)
  • Проверка типов
  • Валидация формата

Это предотвращает повреждение состояния вашего объекта некорректными данными и обеспечивает согласованность вашей программы.

Попробуйте сами

-- Подключить модуль Player
local Player = require('Player')

-- Считать входные данные
local name = io.read()
local healthValue = tonumber(io.read())
local levelValue = tonumber(io.read())

-- TODO: Создать нового игрока с указанным именем

-- TODO: Попытаться установить здоровье игрока в healthValue

-- TODO: Попытаться установить уровень игрока в levelValue

-- TODO: Вывести итоговую статистику игрока в формате:
-- Имя: {name}
-- Здоровье: {finalHealth}
-- Уровень: {finalLevel}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming