Menu
Coddy logo textTech

Gözlemci Deseni

Coddy'nin Ruby Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 44 / 57.

gözlemci deseni, nesnelerin başka bir nesnedeki değişikliklere, yani özneye, abone olmasını sağlar. Özne, gözlemcilerin bir listesini tutar ve ne yaptıklarını bilmeden bir şey olduğunda her birini bilgilendirir:

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

Çıktı:

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

Gözlemcilerin yalnızca bir update yöntemine ihtiyacı vardır: ördek tiplemesi. Her biri tamamen farklı bir sınıf olabilir ve özne değiştirilmeden yeni gözlemciler eklenebilir:

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

thermometer.subscribe(Logger2.new)   # özne değişmedi

Gözlemciler bloklar da olabilir. Özne bunları proc olarak saklar ve call ile çağırır. unsubscribe bir gözlemciyi yeniden kaldırır:

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

Çıktı:

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

Ne gönderileceğine özne karar verir. Öznenin kendisini geçirmek, bir gözlemcinin ihtiyaç duyduğu şeyi okumasını sağlar; bir olay adı geçirmek ise tek bir gözlemcinin çeşitli değişiklik türlerine tepki vermesini sağlar:

@observers.each { |o| o.update(self) }          # gözlemci subject.price okur
@observers.each { |o| o.update(:sold_out, self) }  # gözlemci olayı kontrol eder
challenge icon

Görev

Kolay

Stock sınıfını ve iki gözlemciyi tamamla. Stock.new(symbol), subscribe(observer) ve update_price(value) metotlarına sahiptir; fiyatı saklar ve her gözlemcideki update(stock) çağrılarının nil olmayan yanıtlarını abonelik sırasına göre döndürür. PriceDisplay#update, AAPL now 12.50 değerini döndürür. PriceAlert.new(limit), fiyat limitin altında veya limitteyken limitin üzerine çıktığında ALERT AAPL above 100.00 değerini, aksi takdirde nil döndürür.

İlk girdi satırı sembolü ve uyarı limitini içerir. Sağlanan kod bir ekranı ve bir uyarıyı abone eder, ardından her set price satırı için yanıtları yazdırır.

Kodun stock.rb, price_display.rb ve price_alert.rb dosyalarına yazılmalıdır. main.rb, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

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

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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 iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online Ruby derleyicisi