Patrón Observer
Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 44 de 57.
El patrón observer permite que los objetos se suscriban a los cambios de otro objeto, el subject. El subject mantiene una lista de observers y notifica a cada uno cuando ocurre algo, sin saber qué hacen con ello:
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 = 35Salida:
display: 25 C
display: 35 C
alarm: too hot!Los observadores solo necesitan un método update: tipado pato. Cada uno puede ser una clase completamente diferente, y se pueden añadir nuevos observadores sin cambiar el sujeto:
class Logger2
def update(value)
@history = (@history || []) << value
end
end
thermometer.subscribe(Logger2.new) # el sujeto no ha cambiadoLos observadores también pueden ser bloques. El sujeto los almacena como procs y los llama con call. unsubscribe elimina nuevamente un observador:
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.clickSalida:
["A got clicked", "B got clicked"]
["A got clicked"]El sujeto decide qué enviar. Pasar el sujeto en sí permite que un observador lea lo que necesita; pasar un nombre de evento permite que un observador reaccione a varios tipos de cambios:
@observers.each { |o| o.update(self) } # el observador lee subject.price
@observers.each { |o| o.update(:sold_out, self) } # el observador comprueba el eventoDesafío
FácilCompleta la clase Stock y dos observadores. Stock.new(symbol) tiene subscribe(observer) y update_price(value), que almacena el precio y devuelve las respuestas no nil de update(stock) de cada observador, en el orden de suscripción. PriceDisplay#update devuelve AAPL now 12.50. PriceAlert.new(limit) devuelve ALERT AAPL above 100.00 cuando el precio sube por encima del límite desde un valor igual o inferior a este, y nil en los demás casos.
La primera línea de entrada contiene el símbolo y el límite de alerta. El código proporcionado suscribe una pantalla y una alerta, y después imprime las respuestas de cada línea set price.
Tu código va en stock.rb, price_display.rb y price_alert.rb. main.rb contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
require_relative 'stock'
require_relative 'price_display'
require_relative 'price_alert'
# Código de entrada/salida suministrado: déjalo tal como está
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
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
1Clases y objetos
Trabajar con archivosDefinir clasesVariables de instanciaMétodos y selfto_s e inspectRepaso: tarjeta de biblioteca4Encapsulación
Métodos privadosMétodos protegidosAsignadores privadosProtección del estadoRepaso: máquina expendedora7Polimorfismo y tipado pato
PolimorfismoTipado patoMétodos abstractoscase y clasesRepaso: métodos de pago2Accesores y self
Lectores y escritoresSetters personalizadosself en los métodosIdentidad e igualdadRepaso: lista de contactos5Herencia
SubclasesSobrescritura de métodosLlamar a superis_a? y ancestrosRepaso - Nómina del personal8Métodos especiales
Igualdad y hashMétodos de operadoresIndexación y adiciónColecciones personalizadasRepaso: fracciones11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de Ruby online