Pattern Observer
Fa parte della sezione Programmazione orientata agli oggetti del percorso Ruby di Coddy. Lezione 44 di 57.
Il pattern observer consente agli oggetti di iscriversi alle modifiche di un altro oggetto, il subject. Il soggetto mantiene un elenco di observer e notifica ciascuno di essi quando succede qualcosa, senza sapere cosa ne fanno:
class Thermometer
def initialize
@observers = []
end
def subscribe(observer)
@observers << observer
end
def temperature=(value)
@temperature = value
@observers.each { |o| o.update(value) }
end
end
class Display
def update(value)
puts "display: #{value} C"
end
end
class Alarm
def update(value)
puts "alarm: too hot!" if value > 30
end
end
t = Thermometer.new
t.subscribe(Display.new)
t.subscribe(Alarm.new)
t.temperature = 25
t.temperature = 35Output:
display: 25 C
display: 35 C
alarm: too hot!Agli osservatori serve solo un metodo update: tipizzazione strutturale. Ognuno può essere una classe completamente diversa e si possono aggiungere nuovi osservatori senza modificare il soggetto:
class Logger2
def update(value)
@history = (@history || []) << value
end
end
thermometer.subscribe(Logger2.new) # il soggetto rimane invariatoAnche gli observer possono essere blocchi. Il soggetto li memorizza come proc e li chiama con call. unsubscribe rimuove nuovamente un observer:
class Button
def initialize
@handlers = []
end
def on_click(&handler)
@handlers << handler
handler
end
def unsubscribe(handler)
@handlers.delete(handler)
end
def click
@handlers.map { |h| h.call("clicked") }
end
end
b = Button.new
b.on_click { |e| "A got #{e}" }
second = b.on_click { |e| "B got #{e}" }
p b.click
b.unsubscribe(second)
p b.clickOutput:
["A got clicked", "B got clicked"]
["A got clicked"]Il soggetto decide cosa inviare. Passare il soggetto stesso consente a un osservatore di leggere ciò di cui ha bisogno; passare il nome di un evento consente a un osservatore di reagire a diversi tipi di cambiamenti:
@observers.each { |o| o.update(self) } # l'osservatore legge subject.price
@observers.each { |o| o.update(:sold_out, self) } # l'osservatore controlla l'eventoSfida
FacileCompleta la classe Stock e due osservatori. Stock.new(symbol) ha subscribe(observer) e update_price(value), che memorizza il prezzo e restituisce le risposte diverse da nil di update(stock) per ogni osservatore, nell’ordine di sottoscrizione. PriceDisplay#update restituisce AAPL now 12.50. PriceAlert.new(limit) restituisce ALERT AAPL above 100.00 quando il prezzo supera il limite partendo da un valore pari o inferiore, e nil altrimenti.
La prima riga di input contiene il simbolo e il limite dell’avviso. Il codice fornito sottoscrive una visualizzazione e un avviso, poi stampa le risposte per ogni riga di impostazione del prezzo.
Il tuo codice va in stock.rb, price_display.rb e price_alert.rb. main.rb contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
require_relative 'stock'
require_relative 'price_display'
require_relative 'price_alert'
# Codice di input/output fornito: lascialo così com'è
input = []
while (line = gets)
input << line.chomp
end
symbol, limit = input[0].split
stock = Stock.new(symbol)
stock.subscribe(PriceDisplay.new)
stock.subscribe(PriceAlert.new(limit.to_f))
input.drop(1).each do |line|
stock.update_price(line.split[1].to_f).each { |reply| puts reply }
end
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
1Classi e oggetti
Lavorare con i fileDefinire le classiVariabili d'istanzaMetodi e selfto_s e inspectRipasso - Tessera della biblioteca4Incapsulamento
Metodi privatiMetodi protettiSetter privatiProteggere lo statoRiepilogo - Distributore automatico7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMetodi astratticase e classiRiepilogo - Metodi di pagamento10Pattern di progettazione Parte 2
Delegazione con ForwardablePattern DecoratorPattern BuilderPattern State2Metodi di accesso e self
Metodi di lettura e scritturaSetter personalizzatiself nei metodiIdentità e uguaglianzaRiepilogo - Elenco contatti5Ereditarietà
SottoclassiRidefinizione dei metodiChiamare superis_a? e antenatiRiepilogo - Paghe del personale8Metodi speciali
Uguaglianza e hashMetodi degli operatoriIndicizzazione e appendCollezioni personalizzateRiepilogo - Frazioni11Progetto: Gestione della biblioteca
Libri e iscrittiPrendere in prestito i libriEsercitati da solo: Compilatore Ruby online