Variables de Instancia
Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 12 de 70.
Bienvenido a un nuevo capítulo centrado en cómo los objetos gestionan sus datos internos. Has aprendido a crear clases e instancias; ahora es el momento de explorar cómo cada instancia almacena y gestiona su propio estado único.
Las variables de instancia son campos que pertenecen exclusivamente a un solo objeto. Cuando asignas un valor a self.something dentro de un método o constructor, esos datos viven solo en esa instancia en particular. Otros objetos de la misma clase tienen sus propias copias separadas.
Esto se vuelve especialmente importante al almacenar datos complejos como tablas. Considera un sistema de inventario donde cada personaje lleva diferentes objetos:
local Inventory = {}
Inventory.__index = Inventory
function Inventory:new()
local instance = {}
setmetatable(instance, self)
instance.items = {} -- Cada instancia obtiene su propia tabla vacía
return instance
end
function Inventory:addItem(item)
table.insert(self.items, item)
endLa línea clave es instance.items = {}. Al crear una nueva tabla vacía dentro del constructor, cada objeto de inventario recibe su propia lista distinta. Si en su lugar definieras items en la propia tabla de la clase, todas las instancias compartirían accidentalmente la misma tabla: ¡añadir una espada a un personaje se la daría a todos!
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- Salida: 1
print(#bag2.items) -- Salida: 1Cada inventario mantiene su propia colección. Este patrón se aplica siempre que una instancia necesite realizar un seguimiento de datos que cambian de forma independiente: listas, contadores o cualquier estado mutable único para ese objeto.
Desafío
FácilVamos a construir un sistema de ShoppingCart donde cada carrito mantenga su propia lista separada de productos. Esto demostrará cómo las variables de instancia mantienen los datos aislados entre objetos: ¡agregar artículos a un carrito no afectará a otro!
Organizarás tu código en dos archivos:
ShoppingCart.lua: Define tu claseShoppingCartdonde cada instancia tenga su propia tablaproducts. Incluye:- Un constructor
:new()que inicialice una lista de productos vacía para cada carrito - Un método
:addProduct(productName)que agregue un producto a la lista de este carrito - Un método
:listProducts()que imprima cada producto en una línea separada
- Un constructor
main.lua: Requiere tu módulo ShoppingCart y crea dos carritos separados. Agrega diferentes productos a cada carrito para demostrar que mantienen inventarios independientes.
Recibirás cuatro entradas:
- Primer producto para agregar al carrito A
- Segundo producto para agregar al carrito A
- Primer producto para agregar al carrito B
- Segundo producto para agregar al carrito B
En tu archivo principal:
- Crea dos carritos de compras:
cartAycartB - Agrega los dos primeros productos a
cartA - Agrega los dos últimos productos a
cartB - Imprime
Cart A:y luego enumera los productos del carrito A - Imprime
Cart B:y luego enumera los productos del carrito B
Por ejemplo, si las entradas son Apple, Bread, Milk, y Eggs, la salida debería ser:
Cart A:
Apple
Bread
Cart B:
Milk
EggsRecuerda: la clave es inicializar products como una nueva tabla vacía dentro del constructor. Esto asegura que cada instancia del carrito obtenga su propia lista separada en lugar de compartir una sola tabla entre todos los carritos.
Hoja de referencia
Las variables de instancia son campos que pertenecen exclusivamente a un solo objeto. Cuando asignas un valor a self.something dentro de un método o constructor, esos datos viven solo en esa instancia en particular.
Para crear variables de instancia, inicialízalas dentro del constructor utilizando una nueva tabla para cada instancia:
local Inventory = {}
Inventory.__index = Inventory
function Inventory:new()
local instance = {}
setmetatable(instance, self)
instance.items = {} -- Cada instancia obtiene su propia tabla vacía
return instance
end
function Inventory:addItem(item)
table.insert(self.items, item)
endLa clave es instance.items = {}; crear una nueva tabla vacía dentro del constructor asegura que cada objeto reciba sus propios datos distintos. Si definieras items en la propia tabla de la clase, todas las instancias compartirían la misma tabla.
local bag1 = Inventory:new()
local bag2 = Inventory:new()
bag1:addItem("Sword")
bag2:addItem("Potion")
print(#bag1.items) -- Output: 1
print(#bag2.items) -- Output: 1Cada instancia mantiene su propia colección de forma independiente. Este patrón se aplica a cualquier estado mutable único de un objeto: listas, contadores u otros datos que cambian por instancia.
Pruébalo tú mismo
-- Requerir el módulo ShoppingCart
local ShoppingCart = require('ShoppingCart')
-- Leer entradas
local product1 = io.read()
local product2 = io.read()
local product3 = io.read()
local product4 = io.read()
-- TODO: Crear dos carritos de compras: cartA y cartB
-- TODO: Agregar product1 y product2 a cartA
-- TODO: Agregar product3 y product4 a cartB
-- TODO: Imprimir "Cart A:" luego listar los productos de cartA
-- TODO: Imprimir "Cart B:" luego listar los productos de cartB
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