Padrão Observer
Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 44 de 57.
O padrão observador permite que objetos se inscrevam para receber alterações de outro objeto, o sujeito. O sujeito mantém uma lista de observadores e notifica cada um quando algo acontece, sem saber o que eles fazem com isso:
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 = 35Saída:
display: 25 C
display: 35 C
alarm: too hot!Os observadores precisam apenas de um método update: tipagem pato. Cada um pode ser uma classe completamente diferente, e novos observadores podem ser adicionados sem alterar o sujeito:
class Logger2
def update(value)
@history = (@history || []) << value
end
end
thermometer.subscribe(Logger2.new) # o subject permanece inalteradoOs observadores também podem ser blocos. O sujeito os armazena como procs e os chama com call. unsubscribe remove um observador novamente:
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.clickSaída:
["A got clicked", "B got clicked"]
["A got clicked"]O assunto decide o que enviar. Passar o próprio assunto permite que um observador leia o que precisa; passar um nome de evento permite que um observador reaja a vários tipos de alterações:
@observers.each { |o| o.update(self) } # observer lê subject.price
@observers.each { |o| o.update(:sold_out, self) } # observer verifica o eventoDesafio
FácilComplete o assunto Stock e dois observadores. Stock.new(symbol) possui subscribe(observer) e update_price(value), que armazena o preço e retorna as respostas não-nil de update(stock) de cada observador, na ordem de inscrição. PriceDisplay#update retorna AAPL now 12.50. PriceAlert.new(limit) retorna ALERT AAPL above 100.00 quando o preço sobe acima do limite partindo de um valor igual ou inferior a ele, e nil caso contrário.
A primeira linha de entrada contém o símbolo e o limite do alerta. O código fornecido inscreve um display e um alerta e, em seguida, imprime as respostas para cada linha set price.
Seu código deve estar em stock.rb, price_display.rb e price_alert.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
require_relative 'stock'
require_relative 'price_display'
require_relative 'price_alert'
# Código de entrada/saída fornecido: mantenha-o 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 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
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesVariáveis de InstânciaMétodos e selfto_s e inspectRevisão - Cartão da Biblioteca4Encapsulamento
Métodos privadosMétodos protegidosSetters privadosProtegendo o estadoRevisão - Máquina de venda automática7Polimorfismo e Duck Typing
PolimorfismoDuck TypingMétodos Abstratoscase e ClassesRevisão - Métodos de Pagamento2Acessores e self
Leitores e GravadoresSetters Personalizadosself nos MétodosIdentidade e IgualdadeRecapitulação - Lista de Contatos5Herança
SubclassesSobrescrita de métodosChamando superis_a? e ancestraisRevisão - Folha de pagamento da equipe8Métodos Especiais
Igualdade e hashMétodos de OperadoresIndexação e AdiçãoColeções PersonalizadasRevisão - Frações11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de Ruby online