Menu
CoddyTech

Pola Observer

Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Ruby di Coddy. Pelajaran 44 dari 57.

Pola observer memungkinkan object berlangganan perubahan pada object lain, yaitu subject. Subject menyimpan list observer dan memberi tahu setiap observer saat sesuatu terjadi, tanpa mengetahui apa yang akan mereka lakukan:

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 = 35

Output:

display: 25 C
display: 35 C
alarm: too hot!

Pengamat hanya memerlukan method update: duck typing. Masing-masing bisa berupa class yang benar-benar berbeda, dan pengamat baru bisa ditambahkan tanpa mengubah subjek:

class Logger2
  def update(value)
    @history = (@history || []) << value
  end
end

thermometer.subscribe(Logger2.new)   # subject tetap sama

Observer juga bisa berupa blok. Subject menyimpannya sebagai proc dan memanggilnya dengan call. unsubscribe menghapus 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.click

Output:

["A got clicked", "B got clicked"]
["A got clicked"]

Subject menentukan apa yang akan dikirim. Mengirim subject itu sendiri memungkinkan observer membaca hal yang dibutuhkannya; mengirim nama event memungkinkan satu observer bereaksi terhadap beberapa jenis perubahan:

@observers.each { |o| o.update(self) }          # observer membaca subject.price
@observers.each { |o| o.update(:sold_out, self) }  # observer memeriksa peristiwa tersebut
challenge icon

Tantangan

Mudah

Lengkapi subjek Stock dan dua observer. Stock.new(symbol) memiliki subscribe(observer) dan update_price(value), yang menyimpan harga dan mengembalikan balasan non-nil dari update(stock) pada setiap observer, sesuai urutan langganan. PriceDisplay#update mengembalikan AAPL now 12.50. PriceAlert.new(limit) mengembalikan ALERT AAPL above 100.00 saat harga naik melewati batas dari posisi sama dengan atau di bawahnya, dan nil jika tidak.

Baris input pertama berisi simbol dan batas alert. Kode yang disediakan berlangganan ke display dan alert, lalu mencetak balasan untuk setiap baris set price.

Kodemu ditulis di stock.rb, price_display.rb, dan price_alert.rb. main.rb berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

require_relative 'stock'
require_relative 'price_display'
require_relative 'price_alert'

# Kode input/output yang disediakan: biarkan apa adanya
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
quiz iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Objek

Latihan sendiri: Compiler Ruby online