תבנית Observer
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 44 מתוך 57.
תבנית הצופה מאפשרת לאובייקטים להירשם לקבלת עדכונים על שינויים באובייקט אחר, הנושא. הנושא שומר רשימה של צופים ומודיע לכל אחד מהם כשמשהו קורה, בלי לדעת מה הם עושים עם המידע:
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פלט:
display: 25 C
display: 35 C
alarm: too hot!הצופים צריכים רק מתודת update: טיפוסיות ברווז. כל אחד מהם יכול להיות מחלקה שונה לחלוטין, ואפשר להוסיף צופים חדשים בלי לשנות את הנושא:
class Logger2
def update(value)
@history = (@history || []) << value
end
end
thermometer.subscribe(Logger2.new) # האובייקט הנצפה לא השתנהגם צופים יכולים להיות בלוקים. הנושא שומר אותם כ-procs וקורא להם באמצעות call. unsubscribe מסירה צופה שוב:
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פלט:
["A got clicked", "B got clicked"]
["A got clicked"]הנושא מחליט מה לשלוח. העברת הנושא עצמו מאפשרת למתבונן לקרוא את מה שהוא צריך; העברת שם של אירוע מאפשרת למתבונן אחד להגיב לכמה סוגים של שינויים:
@observers.each { |o| o.update(self) } # ה-observer קורא את subject.price
@observers.each { |o| o.update(:sold_out, self) } # ה-observer בודק את האירועאתגר
קלהשלם את המחלקה Stock ושני צופים. למחלקה Stock.new(symbol) יש את subscribe(observer) ואת update_price(value), ששומרת את המחיר ומחזירה את התשובות שאינן nil של update(stock) מכל צופה, לפי סדר ההרשמה. PriceDisplay#update מחזירה את AAPL now 12.50. PriceAlert.new(limit) מחזירה את ALERT AAPL above 100.00 כשהמחיר עולה מעל המגבלה לאחר שהיה שווה לה או נמוך ממנה, ואת nil אחרת.
שורת הקלט הראשונה מכילה את הסימול ואת מגבלת ההתראה. הקוד שסופק רושם צג והתראה, ואז מדפיס את התשובות עבור כל שורת מחיר.
הקוד שלך צריך להופיע בקבצים stock.rb, price_display.rb ו-price_alert.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
require_relative 'stock'
require_relative 'price_display'
require_relative 'price_alert'
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
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
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
3מתודות ומשתנים של מחלקה
מתודות של מחלקהמשתני מופע של מחלקהקבועיםמתודות ליצירת מופעיםסיכום – קודי קופוןתרגלו בעצמכם: קומפיילר Ruby אונליין