Паттерны проектирования в Ruby: Наблюдатель (Observer)

6 ноября 2015, пятница

Следующий поведенческий шаблон проектирования — Наблюдатель. Определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом событии.

Рассмотрим пример из официальной документации. У нас есть класс Ticker, который будет менять цену и оповещать об изменении наблюдателей WarnLow и WarnHigh, которые будут выводить соответствующие сообщения в случае с выходом цена за заданные пределы.

require "observer"
class Ticker ### Periodically fetch a stock price.
  include Observable

  def initialize(symbol)
    @symbol = symbol
  end

  def run
    lastPrice = nil
    10.times do
      price = Price.fetch(@symbol)
      print "Current price: #{price}\n"
      if price != lastPrice
        changed # notify observers
        lastPrice = price
        notify_observers(Time.now, price)
      end
      sleep 1
    end
  end
end
class Price ### A mock class to fetch a stock price (60 - 140).
  def Price.fetch(symbol)
    60 + rand(80)
  end
end
class Warner ### An abstract observer of Ticker objects.
  def initialize(ticker, limit)
    @limit = limit
    ticker.add_observer(self)
  end

  def update(time, price)
    raise 'Method "update" must be implemented!'
  end
end

class WarnLow < Warner
  def update(time, price) # callback for observer
    if price < @limit
      print "--- #{time.to_s}: Price below #{@limit}: #{price}\n"
    end
  end
end

class WarnHigh < Warner
  def update(time, price) # callback for observer
    if price > @limit
      print "+++ #{time.to_s}: Price above #{@limit}: #{price}\n"
    end
  end
end

Теперь попробуем создать новый объект класса Ticker и запустить процесс изменения цены.

ticker = Ticker.new("MSFT")
WarnLow.new(ticker, 80)
WarnHigh.new(ticker, 120)
ticker.run

=begin
Результат
Current price: 72
--- 2015-11-07 12:27:14 +0300: Price below 80: 72
Current price: 124
+++ 2015-11-07 12:27:15 +0300: Price above 120: 124
Current price: 90
Current price: 96
Current price: 91
Current price: 77
--- 2015-11-07 12:27:19 +0300: Price below 80: 77
Current price: 98
Current price: 88
Current price: 94
Current price: 67
--- 2015-11-07 12:27:23 +0300: Price below 80: 67
=end

Таким образом шаблон Наблюдатель применяется в тех случаях, когда существует как минимум один объект, рассылающий сообщения, и имеется несколько получателей сообщений, причем их количество и состав могут меняться во время работы приложения. Отправителя при этом не интересует, что будут делать получатели с предоставленной информацей.