Relación "Tiene-Un"
Parte de la sección Programación Orientada a Objetos del Journey de Lua de Coddy. Lección 49 de 70.
A lo largo de este curso, has usado la herencia para compartir comportamiento entre clases: un Dog «es un» Animal. Pero la herencia no siempre es la herramienta adecuada.
A veces, los objetos no comparten un árbol genealógico; en su lugar, un objeto simplemente contiene a otro. Esto se llama composición y modela una relación de «tiene un».
Considera un automóvil. Un automóvil no es un tipo de motor. tiene un motor. El motor es un objeto separado que existe dentro del automóvil:
local Engine = {}
Engine.__index = Engine
function Engine:new(horsepower)
local obj = {horsepower = horsepower}
setmetatable(obj, Engine)
return obj
end
local Car = {}
Car.__index = Car
function Car:new(model, engine)
local obj = {
model = model,
engine = engine -- Almacena el objeto Engine dentro de Car
}
setmetatable(obj, Car)
return obj
endAl crear un coche, pasas un objeto de motor existente a su constructor:
local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)
print(myCar.engine.horsepower) -- 200El automóvil no hereda del motor. Simplemente mantiene una referencia a él. Esto mantiene ambas clases independientes. Podrías sustituirlo por un motor diferente o usar la misma clase de motor en una motocicleta.
La composición te ofrece una flexibilidad que la herencia no puede: ensamblas objetos a partir de partes en lugar de encasillarlos en una jerarquía familiar rígida.
Desafío
Fácil¡Construyamos un sistema informático usando composición! En lugar de herencia, crearás una Computer que tiene una CPU dentro: demostrando la relación «tiene-un».
Organizarás tu código en tres archivos:
CPU.lua: Crea una clase CPU con un constructor:new(brand, speed)que almacene el nombre de la marca y la velocidad en GHz. Incluye un método:getInfo()que devuelva una cadena con el formato:{brand} @ {speed}GHzComputer.lua: Crea una clase Computer cuyo constructor:new(model, cpu)acepte un nombre de modelo y un objeto CPU. Computer almacena el objeto CPU dentro de sí mismo (¡composición!). Incluye un método:describe()que muestre el modelo del ordenador y la información de su CPU.main.lua: ¡Une todos los elementos! Lee las entradas correspondientes a la marca de la CPU, la velocidad de la CPU y el modelo del ordenador. Crea primero un objeto CPU y después pásalo al constructor de Computer. Por último, llama al método:describe()del ordenador.
Recibirás tres entradas:
- La marca de la CPU (una cadena)
- La velocidad de la CPU en GHz (un número)
- El nombre del modelo del ordenador (una cadena)
Tu salida debe mostrar la descripción del ordenador, que incluye información de su CPU contenida:
Model: {model}
CPU: {brand} @ {speed}GHzPor ejemplo, si las entradas son Intel, 3.5 y WorkStation, la salida debe ser:
Model: WorkStation
CPU: Intel @ 3.5GHzObserva que Computer no hereda de CPU. Simplemente mantiene una referencia a una. El método :describe() de Computer accede a los datos de la CPU a través del objeto almacenado, mostrando cómo la composición te permite construir objetos complejos a partir de partes más sencillas.
Pruébalo tú mismo
-- main.lua
-- Reúne todo usando composición
local CPU = require('CPU')
local Computer = require('Computer')
-- Leer entradas
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()
-- TODO: Crea un objeto CPU con la marca y la velocidad
-- TODO: Crea un objeto Computer con el modelo y el objeto CPU
-- TODO: Llama al método describe() de la computadora para imprimir la salida
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
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 formas9Composición y Mixins
Relación "Tiene-Un"DelegaciónMixins simplesAplicación de múltiples MixinsMixins vs. HerenciaResumen - Ensamblaje de robotsPractica por tu cuenta: Compilador de Lua online