Compartido vs. Único
Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 35 de 70.
Al trabajar con la herencia, es importante entender dónde reside cada fragmento de datos. Algunos atributos son compartidos: definidos en el padre y accesibles para todos los hijos. Otros son únicos: creados específicamente en la clase hija o instancia.
Considera esta jerarquía:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Compartido: definido en la clase
function Animal:new(name)
local obj = {name = name} -- Único: almacenado en cada instancia
setmetatable(obj, Animal)
return obj
endlocal Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Compartido entre todos los Dogs
function Dog:new(name, breed)
local obj = Animal.new(Animal, name)
obj.breed = breed -- Único: cada Dog tiene su propia raza
setmetatable(obj, Dog)
return obj
endCuando creas una instancia de Dog, algunos valores existen directamente en el objeto, mientras que otros se encuentran a través de la cadena de búsqueda (lookup chain):
local rex = Dog:new("Rex", "German Shepherd")
-- Único para esta instancia (almacenado en rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"-- Compartido (encontrado mediante búsqueda)
print(rex.sound) -- "bark" (de Dog)
print(rex.kingdom) -- "Animalia" (de Animal)La distinción clave: los campos asignados a obj en los constructores son únicos para cada instancia, mientras que los campos definidos directamente en las tablas de clase se comparten entre todas las instancias de esa clase y sus hijos.
Desafío
FácilExploremos cómo fluyen los datos a través de una jerarquía de herencia construyendo un sistema de clases Creature y Dragon. Verás de primera mano qué atributos se comparten entre todas las instancias y cuáles son únicos para cada objeto individual.
Organizarás tu código en tres archivos:
Creature.lua: Define tu clase padre con un atributo compartido a nivel de claseworld = "Fantasy Realm"que todas las criaturas comparten. Incluye un constructor:new(name)que almacene el nombre de la criatura como un atributo de instancia.Dragon.lua: Define tu clase hija que hereda de Creature. Añade un atributo compartido a nivel de claseelement = "fire"que todos los dragones comparten. Tu constructor:new(name, color)debe llamar al constructor padre para el nombre, y luego añadircolorcomo un atributo de instancia único para cada dragón.main.lua: Crea dos dragones diferentes e inspecciona sus atributos para demostrar la diferencia entre datos compartidos y únicos.
Recibirás dos entradas:
- El nombre y color del primer dragón, separados por una coma (por ejemplo,
Smaug,red) - El nombre y color del segundo dragón, separados por una coma (por ejemplo,
Draco,gold)
En tu archivo principal, crea ambos dragones con sus respectivos nombres y colores. Luego imprime la siguiente información en este orden exacto:
namedel primer dragóncolordel primer dragónnamedel segundo dragóncolordel segundo dragónelementdel primer dragón (compartido de la clase Dragon)elementdel segundo dragón (compartido de la clase Dragon)worlddel primer dragón (compartido de la clase Creature)
Por ejemplo, si las entradas son Smaug,red y Draco,gold, la salida debería ser:
Smaug
red
Draco
gold
fire
fire
Fantasy RealmObserva cómo name y color son diferentes para cada dragón (atributos de instancia únicos), mientras que element y world son iguales para ambos (atributos de clase compartidos encontrados a través de la cadena de búsqueda).
Hoja de referencia
En las jerarquías de herencia, los atributos pueden ser **compartidos** (definidos en la tabla de la clase) o **únicos** (almacenados en instancias individuales).
Atributos compartidos se definen directamente en las tablas de clase y se accede a ellos a través de la cadena de búsqueda de metatablas:
local Animal = {}
Animal.__index = Animal
Animal.kingdom = "Animalia" -- Compartido por todos los AnimalsAtributos únicos se asignan al objeto de instancia (obj) en los constructores:
function Animal:new(name)
local obj = {name = name} -- Único para cada instancia
setmetatable(obj, Animal)
return obj
endLas clases hijas pueden tener sus propios atributos compartidos mientras heredan los atributos del padre:
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
Dog.sound = "bark" -- Compartido entre todos los Dogs
function Dog:new(name, breed)
local obj = Animal.new(Animal, name) -- Llamar al constructor padre
obj.breed = breed -- Añadir atributo único de la hija
setmetatable(obj, Dog)
return obj
endAcceso a los atributos:
local rex = Dog:new("Rex", "German Shepherd")
-- Único (almacenado directamente en rex)
print(rex.name) -- "Rex"
print(rex.breed) -- "German Shepherd"
-- Compartido (encontrado mediante búsqueda en metatabla)
print(rex.sound) -- "bark" (de la clase Dog)
print(rex.kingdom) -- "Animalia" (de la clase Animal)Pruébalo tú mismo
-- main.lua: Crea dragones y demuestra atributos compartidos vs únicos
local Dragon = require('Dragon')
-- Leer entrada para el primer dragón (nombre,color)
local input1 = io.read()
-- Leer entrada para el segundo dragón (nombre,color)
local input2 = io.read()
-- TODO: Analizar la primera entrada para extraer el nombre y el color
-- Sugerencia: Usar string.match con el patrón "([^,]+),([^,]+)"
-- TODO: Analizar la segunda entrada para extraer el nombre y el color
-- TODO: Crear el primer dragón con su nombre y color
-- TODO: Crear el segundo dragón con su nombre y color
-- TODO: Imprimir lo siguiente en orden:
-- 1. Nombre del primer dragón
-- 2. Color del primer dragón
-- 3. Nombre del segundo dragón
-- 4. Color del segundo dragón
-- 5. Elemento del primer dragón (compartido de la clase Dragon)
-- 6. Elemento del segundo dragón (compartido de la clase Dragon)
-- 7. Mundo del primer dragón (compartido de la clase Creature)
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