Delega
Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 50 di 70.
Memorizzare un oggetto all'interno di un altro oggetto è solo il primo passo. Il vero potere della composizione deriva dalla delegazione, quando l'oggetto esterno inoltra le chiamate ai metodi ai suoi componenti interni.
Pensa ad avviare un'auto. Non metti le mani sotto il cofano per far girare manualmente il motore. Invece, giri la chiave e l'auto fa il resto da sola.
Nel codice, questo significa che la classe Car fornisce un semplice metodo :start() che delega il lavoro effettivo al motore:
function Car:start()
print("Turning the key...")
self.engine:run() -- Delega all'oggetto interno
endL'auto non ha bisogno di sapere come funziona il motore. Dice semplicemente al motore di fare il suo lavoro. In questo modo le responsabilità restano separate. La classe Engine gestisce la logica del motore, mentre Car coordina i componenti:
function Engine:run()
print("Engine running at " .. self.horsepower .. " HP")
end
local engine = Engine:new(250)
local car = Car:new("Coupe", engine)
car:start()
-- Output:
-- Girando la chiave...
-- Motore in funzione a 250 HPLa delega crea un'interfaccia pulita per gli utenti della tua classe. Interagiscono con l'auto, non con le sue parti interne. Se in seguito sostituisci l'implementazione del motore con una diversa, l'interfaccia pubblica dell'auto rimane invariata: cambia solo la delega interna.
Sfida
FacileCostruiamo un sistema di riproduzione musicale che dimostra la delega! Creerai un componente Speaker e un MusicPlayer che lo contiene. Il lettore non gestirà direttamente l’uscita audio; delegherà invece questa responsabilità al suo altoparlante interno.
Organizzerai il codice in tre file:
Speaker.lua: crea una classe Speaker con un costruttore:new(volume)che memorizza il livello del volume. Includi un metodo:playSound(trackName)che stampa:Playing "{trackName}" at volume {volume}MusicPlayer.lua: crea una classe MusicPlayer il cui costruttore:new(brand, speaker)accetta un nome di marca e un oggetto Speaker. Il lettore memorizza l’altoparlante al suo interno. Includi questi metodi::play(trackName): stampa{brand} player starting..., quindi delega al metodo:playSound()dell’altoparlante:stop(): stampa{brand} player stopped
main.lua: metti insieme tutto! Leggi gli input per il volume dell’altoparlante, la marca del lettore e il nome di una traccia. Crea prima uno Speaker, poi passalo al costruttore di MusicPlayer. Chiama il metodo:play()del lettore con il nome della traccia, poi chiama:stop().
Riceverai tre input:
- Il volume dell’altoparlante (un numero)
- La marca del lettore musicale (una stringa)
- Il nome della traccia da riprodurre (una stringa)
L’output dovrebbe mostrare il lettore che coordina il lavoro con il suo altoparlante:
{brand} player starting...
Playing "{trackName}" at volume {volume}
{brand} player stoppedAd esempio, se gli input sono 75, SoundMax e Summer Vibes, l’output dovrebbe essere:
SoundMax player starting...
Playing "Summer Vibes" at volume 75
SoundMax player stoppedNota che MusicPlayer non sa come produrre il suono. Dice semplicemente al suo altoparlante di occuparsene. Questa è la delega in azione: l’oggetto esterno offre un’interfaccia semplice, mentre il componente interno svolge il lavoro specializzato!
Provalo tu
-- main.lua
-- Metti tutto insieme!
local Speaker = require('Speaker')
local MusicPlayer = require('MusicPlayer')
-- Leggi gli input
local volume = tonumber(io.read())
local brand = io.read()
local trackName = io.read()
-- TODO: Crea uno Speaker con il volume indicato
-- TODO: Crea un MusicPlayer con brand e speaker
-- TODO: Chiama il metodo play del lettore con il nome della traccia
-- TODO: Chiama il metodo stop del lettore
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Il concetto di «self»
Tabelle con funzioni«self» esplicitoLa sintassi dei due puntiPunto o due puntiRiepilogo - Spostare il punto4Progetto: Banca digitale
Configurazione del progettoMetodo di deposito2Schema del prototipo di classe
Il concetto di prototipoCollegare con __indexIl costruttore :new()Inizializzare gli attributiIstanze indipendentiRiepilogo - Fabbrica di auto5Sovraccarico degli operatori nella OOP
Sommare oggettiSottrarre oggettiConcatenare oggettiConfrontare oggetti (<, >)Ripasso - Calcoli con il portafoglio8Incapsulamento
Convenzioni di denominazioneClosure per la privacyAccesso tramite closureTabelle di sola letturaLogica di convalidaRiepilogo - Cassaforte sicura11Modelli di progettazione (base)
Funzioni factoryTabella singletonPattern IteratorObserver (listener)Riepilogo - Factory per logger3Stato e comportamento degli oggetti
Variabili di istanzaMetodi getterMetodi setterProprietà calcolateFormattazione delle stringheControlli di uguaglianzaRiepilogo - Voto dello studente6Fondamenti dell'ereditarietà
Configurare l'ereditarietàEreditare i metodiEstendere il costruttoreAggiungere metodi alla classe figliaCondiviso vs specificoRiepilogo - Gerarchia delle forme9Composizione e mixin
Relazione Has-ADelegaMixin sempliciApplicare più mixinMixin vs ereditarietàRiepilogo - Assemblaggio di robotEsercitati da solo: Compilatore Lua online