Propiedades Calculadas
Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 15 de 70.
Los getters y setters proporcionan acceso a los valores almacenados, pero a veces necesitas datos que no existen como un campo almacenado; necesitan ser calculados a partir de otros atributos. Estas se denominan propiedades calculadas.
Considera un rectángulo. Almacenas su ancho y su alto, pero el área no se almacena en ningún lugar; se calcula multiplicando estos dos valores. En lugar de almacenar datos redundantes, creas un método que calcula y devuelve el resultado:
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
endEl método :getArea() no devuelve un valor almacenado—calcula el área de nuevo cada vez que lo llamas. Este enfoque tiene una ventaja clave: si el ancho o el alto cambian, el área refleja automáticamente las nuevas dimensiones sin que necesites actualizar nada.
local box = Rectangle:new(5, 3)
print(box:getArea()) -- Salida: 15
box.width = 10
print(box:getArea()) -- Salida: 30Las propiedades calculadas mantienen la consistencia de tus objetos. En lugar de almacenar valores que dependen de otros campos (y arriesgarse a que queden desactualizados), los calculas bajo demanda. Este patrón se aplica a cualquier dato derivado: perímetros, promedios, cadenas formateadas o cualquier valor que pueda determinarse a partir de atributos existentes.
Desafío
Fácil¡Vamos a construir una clase Box que calcule su volumen bajo demanda! En lugar de almacenar el volumen como un campo, crearás una propiedad calculada que lo compute a partir de las dimensiones de la caja cada vez que sea necesario.
Organizarás tu código en dos archivos:
Box.lua: Define tu claseBoxcon el patrón de prototipo estándar. Cada caja almacena tres dimensiones:width,heightydepth. Incluye:- Un constructor
:new(width, height, depth)que almacene las tres dimensiones - Un método
:getVolume()que calcule y devuelva el volumen (width × height × depth) - Un método
:getSurfaceArea()que calcule y devuelva el área de superficie total
- Un constructor
main.lua: Requiere tu módulo Box, crea una instancia de la caja y demuestra cómo las propiedades calculadas reflejan automáticamente las dimensiones actuales.
El área de superficie de una caja se calcula como: 2 × (width×height + height×depth + width×depth)
Recibirás tres entradas que representan las dimensiones de la caja:
- Ancho (Width)
- Alto (Height)
- Profundidad (Depth)
En tu archivo principal, crea una caja con las dimensiones dadas, luego imprime dos líneas:
- El volumen usando
:getVolume() - El área de superficie usando
:getSurfaceArea()
Por ejemplo, si las entradas son 3, 4 y 5, la salida debería ser:
60
94La belleza de las propiedades calculadas es que siempre se mantienen precisas. Si más tarde cambiaras una de las dimensiones de la caja, llamar a :getVolume() de nuevo devolvería automáticamente el nuevo valor correcto, ¡sin necesidad de actualizaciones manuales!
Hoja de referencia
Las propiedades calculadas son métodos que calculan y devuelven valores basados en otros atributos en lugar de almacenarlos directamente. Esto asegura la consistencia de los datos y elimina la redundancia.
Ejemplo de una propiedad calculada para el área:
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
endEl método :getArea() calcula el área cada vez que se llama, reflejando automáticamente cualquier cambio en el ancho o el alto:
local box = Rectangle:new(5, 3)
print(box:getArea()) -- Resultado: 15
box.width = 10
print(box:getArea()) -- Resultado: 30Las propiedades calculadas son útiles para cualquier dato derivado, como perímetros, volúmenes, promedios o cadenas formateadas que puedan determinarse a partir de los atributos existentes.
Pruébalo tú mismo
-- Requerir el módulo Box
local Box = require('Box')
-- Leer las dimensiones de entrada
local width = tonumber(io.read())
local height = tonumber(io.read())
local depth = tonumber(io.read())
-- TODO: Crear una instancia de box con las dimensiones dadas
-- TODO: Imprimir el volumen usando :getVolume()
-- TODO: Imprimir el área de superficie usando :getSurfaceArea()
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
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 formas