Relacionamento Tem-Um
Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy — lição 49 de 70.
Ao longo deste curso, você usou herança para compartilhar comportamento entre classes—um Dog "é um" Animal. Mas a herança nem sempre é a ferramenta certa.
Às vezes, os objetos não compartilham uma árvore genealógica; em vez disso, um objeto simplesmente contém outro. Isso é chamado de composição, e modela um relacionamento "tem-um".
Considere um carro. Um carro não é um tipo de motor — ele tem um motor. O motor é um objeto separado que existe dentro do carro:
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 -- Armazena o objeto Engine dentro de Car
}
setmetatable(obj, Car)
return obj
endAo criar um carro, você passa um objeto de motor existente para o seu construtor:
local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)
print(myCar.engine.horsepower) -- 200O carro não herda do motor — ele simplesmente mantém uma referência a um. Isso mantém ambas as classes independentes. Você poderia trocar por um motor diferente, ou usar a mesma classe de motor em uma motocicleta.
A composição oferece uma flexibilidade que a herança não consegue proporcionar: você está montando objetos a partir de partes, em vez de prendê-los em uma hierarquia familiar rígida.
Desafio
FácilVamos construir um sistema de computador usando composição! Em vez de herança, você criará um Computer que tem uma CPU dentro dele — demonstrando o relacionamento "tem-um" (has-a).
Você organizará seu código em três arquivos:
CPU.lua: Crie uma classe CPU com um construtor:new(brand, speed)que armazena o nome da marca e a velocidade em GHz. Inclua um método:getInfo()que retorna uma string no formato:{brand} @ {speed}GHzComputer.lua: Crie uma classe Computer cujo construtor:new(model, cpu)aceita um nome de modelo e um objeto CPU. O Computer armazena o objeto CPU dentro de si (composição!). Inclua um método:describe()que imprime o modelo do computador e as informações de sua CPU.main.lua: Junte tudo! Leia as entradas para a marca da CPU, a velocidade da CPU e o modelo do computador. Crie um objeto CPU primeiro e, em seguida, passe-o para o construtor do Computer. Por fim, chame o método:describe()do computador.
Você receberá três entradas:
- A marca da CPU (uma string)
- A velocidade da CPU em GHz (um número)
- O nome do modelo do computador (uma string)
Sua saída deve mostrar a descrição do computador, que inclui informações de sua CPU contida:
Model: {model}
CPU: {brand} @ {speed}GHzPor exemplo, se as entradas forem Intel, 3.5, e WorkStation, a saída deve ser:
Model: WorkStation
CPU: Intel @ 3.5GHzObserve como o Computer não herda de CPU — ele simplesmente mantém uma referência a uma. O método :describe() do Computer acessa os dados da CPU por meio do objeto armazenado, mostrando como a composição permite construir objetos complexos a partir de partes mais simples!
Experimente você mesmo
-- main.lua
-- Reúne tudo usando composição
local CPU = require('CPU')
local Computer = require('Computer')
-- Ler entradas
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()
-- TODO: Criar um objeto CPU com a marca e a velocidade
-- TODO: Criar um objeto Computer com o modelo e o objeto CPU
-- TODO: Chamar o método describe() do computador para imprimir a saída
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1O Conceito 'Self'
Tabelas com Funções'self' ExplícitoA Sintaxe de Dois-pontosPonto vs Dois-pontosRecapitulação - Movendo o Ponto4Projeto: Banco Digital
Configuração do ProjetoMétodo de Depósito7Polimorfismo e Sobrescrita
Sobrescrita de MétodosChamando Métodos da Classe PaiDuck TypingInterface ComumVerificando o TipoRecapitulação - Papéis de Funcionários10Projeto: Gerenciador de Formas
Configuração do ProjetoClasse RetânguloClasse CírculoMétodo PerímetroColeção de FormasÁrea TotalFiltrar Formas2Padrão de Protótipo de Classe
O Conceito de ProtótipoVinculando com __indexO Construtor :new()Inicializando AtributosInstâncias IndependentesRecapitulação - Fábrica de Carros5Sobrecarga de Operadores em POO
Somando ObjetosSubtraindo ObjetosConcatenando ObjetosComparando Objetos (<, >)Recapitulação - Matemática de Carteira8Encapsulamento
Convenções de NomenclaturaClosures para PrivacidadeAcesso via ClosuresTabelas Somente LeituraLógica de ValidaçãoRecapitulação - Cofre Seguro11Padrões de Projeto (Lite)
Funções FactoryTabela SingletonPadrão IteratorObserver (Listener)Recapitulação - Logger Factory3Estado e Comportamento do Objeto
Variáveis de InstânciaMétodos GetterMétodos SetterPropriedades CalculadasFormatação de StringsVerificações de IgualdadeRecapitulação - Nota do Aluno6Fundamentos de Herança
Configurando a HerançaHerdando MétodosEstendendo o ConstrutorAdicionando Métodos FilhosCompartilhado vs ÚnicoRecapitulação - Hierarquia de Formas9Composição e Mixins
Relacionamento Tem-UmDelegaçãoMixins SimplesAplicando Múltiplos MixinsMixins vs HerançaRecapitulação - Montagem de Robô