Menu
Coddy logo textTech

Вычисляемые свойства

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

Геттеры и сеттеры обеспечивают доступ к сохраненным значениям, но иногда вам нужны данные, которые не существуют в виде сохраненного поля — их нужно вычислять на основе других атрибутов. Они называются вычисляемыми свойствами.

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

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle:new(width, height)
    local instance = {}
    setmetatable(instance, self)
    instance.width = width
    instance.height = height
    return instance
end

function Rectangle:getArea()
    return self.width * self.height
end

Метод :getArea() не возвращает сохраненное значение — он вычисляет площадь заново при каждом вызове. У этого подхода есть ключевое преимущество: если ширина или высота изменяются, площадь автоматически отражает новые размеры без необходимости что-либо обновлять вручную.

local box = Rectangle:new(5, 3)
print(box:getArea())  -- Вывод: 15

box.width = 10
print(box:getArea())  -- Вывод: 30

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

challenge icon

Задание

Легко

Давайте создадим класс Box, который вычисляет свой объем по запросу! Вместо того чтобы хранить объем как поле, вы создадите вычисляемое свойство, которое рассчитывает его на основе размеров коробки всякий раз, когда это необходимо.

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

  • Box.lua: Определите класс Box, используя стандартный паттерн прототипа. Каждая коробка хранит три измерения: width, height и depth. Включите:
    • Конструктор :new(width, height, depth), который сохраняет все три измерения
    • Метод :getVolume(), который вычисляет и возвращает объем (width × height × depth)
    • Метод :getSurfaceArea(), который вычисляет и возвращает общую площадь поверхности
  • main.lua: Подключите модуль Box, создайте экземпляр коробки и продемонстрируйте, как вычисляемые свойства автоматически отражают текущие размеры.

Площадь поверхности коробки вычисляется по формуле: 2 × (width×height + height×depth + width×depth)

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

  1. Ширина (Width)
  2. Высота (Height)
  3. Глубина (Depth)

В основном файле создайте коробку с заданными размерами, затем выведите две строки:

  1. Объем, используя :getVolume()
  2. Площадь поверхности, используя :getSurfaceArea()

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

60
94

Прелесть вычисляемых свойств заключается в том, что они всегда остаются точными. Если вы позже измените один из размеров коробки, повторный вызов :getVolume() автоматически вернет правильное новое значение — никаких ручных обновлений не требуется!

Шпаргалка

Вычисляемые свойства — это методы, которые вычисляют и возвращают значения на основе других атрибутов, а не хранят их напрямую. Это обеспечивает согласованность данных и устраняет избыточность.

Пример вычисляемого свойства для площади:

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle:new(width, height)
    local instance = {}
    setmetatable(instance, self)
    instance.width = width
    instance.height = height
    return instance
end

function Rectangle:getArea()
    return self.width * self.height
end

Метод :getArea() вычисляет площадь при каждом вызове, автоматически отражая любые изменения ширины или высоты:

local box = Rectangle:new(5, 3)
print(box:getArea())  -- Output: 15

box.width = 10
print(box:getArea())  -- Output: 30

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

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

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

-- Прочитать входные размеры
local width = tonumber(io.read())
local height = tonumber(io.read())
local depth = tonumber(io.read())

-- TODO: Создать экземпляр коробки с заданными размерами

-- TODO: Вывести объем, используя :getVolume()

-- TODO: Вывести площадь поверхности, используя :getSurfaceArea()
quiz iconПроверьте себя

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

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