Spec-Zone.ru › Ruby 2.3

модуль Observable

Шаблон наблюдателя (также известный как публикация/подписка) предоставляет простой механизм, позволяющий одному объекту уведомлять набор заинтересованных сторонних объектов об изменениях своего состояния.

Механизм

Уведомляющий класс смешивает модуль Observable, который предоставляет методы для управления связанными наблюдателями.

Объект наблюдаемого должен:

  • убедиться, что у него есть #changed

  • вызвать #notify_observers

Наблюдатель подписывается на обновления с помощью #add_observer, который также указывает вызываемый метод через notify_observers. По умолчанию для notify_observers используется метод update.

Пример

Следующий пример наглядно демонстрирует это. Ticker, при запуске, непрерывно получает Price акций для своего @symbol. Warner - это общий наблюдатель цены, и показаны два предупредителя: WarnLow и WarnHigh, которые выдают предупреждение, если цена ниже или выше установленных ими пределов соответственно.

Обратный вызов update позволяет предупредителям работать без явного вызова. Система настроена с Ticker и несколькими наблюдателями, и наблюдатели выполняют свою работу без вмешательства кода верхнего уровня.

Обратите внимание, что договор между издателем и подписчиком (наблюдаемым и наблюдателем) не объявлен и не применяется. Ticker публикует время и цену, а предупредители их получают. Но если вы не гарантируете правильность своих договоров, ничего другого не сможет вас предупредить.

require "observer"

class Ticker          ### Periodically fetch a stock price.
  include Observable

  def initialize(symbol)
    @symbol = symbol
  end

  def run
    last_price = nil
    loop do
      price = Price.fetch(@symbol)
      print "Current price: #{price}\n"
      if price != last_price
        changed                 # notify observers
        last_price = 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 self.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
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.new("MSFT")
WarnLow.new(ticker, 80)
WarnHigh.new(ticker, 120)
ticker.run

Результат:

Current price: 83
Current price: 75
--- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75
Current price: 90
Current price: 134
+++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134
Current price: 134
Current price: 112
Current price: 79
--- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79

Методы публичного экземпляра

add_observer(observer, func=:update) Показать исходный код
# File lib/observer.rb, line 128
def add_observer(observer, func=:update)
  @observer_peers = {} unless defined? @observer_peers
  unless observer.respond_to? func
    raise NoMethodError, "observer does not respond to `#{func}'"
  end
  @observer_peers[observer] = func
end

Добавить observer в качестве наблюдателя этого объекта, чтобы он получал уведомления.

observer

объект, который будет получать уведомления об изменениях.

func

Символ с именем метода, который будет вызываться при изменении этого Observable.

Этот метод должен возвращать true для observer.respond_to? и получит *arg при вызове notify_observers, где *arg - значение, переданное notify_observers этим Observable

changed(state=true) Показать исходный код
# File lib/observer.rb, line 169
def changed(state=true)
  @observer_state = state
end

Установить состояние изменения этого объекта. Уведомления будут отправляться только в том случае, если состояние изменения state равно true.

state

Булево значение, указывающее состояние изменения этого Observable.

changed?() Показать исходный код
# File lib/observer.rb, line 177
def changed?
  if defined? @observer_state and @observer_state
    true
  else
    false
  end
end

Возвращает true, если состояние этого объекта было изменено с момента последнего вызова notify_observers.

count_observers() Показать исходный код
# File lib/observer.rb, line 155
def count_observers
  if defined? @observer_peers
    @observer_peers.size
  else
    0
  end
end

Возвращает количество наблюдателей, связанных с этим объектом.

delete_observer(observer) Показать исходный код
# File lib/observer.rb, line 141
def delete_observer(observer)
  @observer_peers.delete observer if defined? @observer_peers
end

Удалить observer как наблюдателя этого объекта, чтобы он больше не получал уведомлений.

observer

Наблюдатель этого Observable

delete_observers() Показать исходный код
# File lib/observer.rb, line 148
def delete_observers
  @observer_peers.clear if defined? @observer_peers
end

Удалить всех наблюдателей, связанных с этим объектом.

notify_observers(*arg) Показать исходный код
# File lib/observer.rb, line 193
def notify_observers(*arg)
  if defined? @observer_state and @observer_state
    if defined? @observer_peers
      @observer_peers.each do |k, v|
        k.send v, *arg
      end
    end
    @observer_state = false
  end
end

Уведомление наблюдателей об изменении состояния если состояние изменения этого объекта равно true.

Это вызовет метод, указанный в add_observer, передав *arg. Состояние изменения затем устанавливается в false.

*arg

Любые аргументы, которые нужно передать наблюдателям.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API