Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Ruby.docx
Скачиваний:
19
Добавлен:
06.09.2019
Размер:
1.74 Mб
Скачать

20.2. Пример: эмуляция биржевой ленты

В этом примере сервер публикует в сети биржевые котировки акций. К серверу может обратиться любой клиент, желающий узнать, сколько сейчас стоит его пакет.

Но мы добавили одну тонкость. Не желая следить за малейшими колебаниями цен, мы реализовали модуль Observer, который позволяет подписаться на информационный канал. Клиент следит за поступающими сведениями и предупреждает нас, когда изменение цены превысит заданный порог.

Сначала рассмотрим модуль DrbObservable. Это прямолинейная реализация паттерна Observer (Наблюдатель), описанного в замечательной книге Э. Гаммы, Р. Хелма, Р. Джонсона и Дж. Влиссидеса «Паттерны проектирования» (см. сноску в разделе 12.3.1). Еще этот паттерн называют «Издатель-Подписчик».

В листинге 20.1 наблюдатель определен как объект, отвечающий на вызов метода update. Сервер добавляет наблюдателей по их просьбе и посылает им уведомления, обращаясь к методуnotify_observers.

Листинг 20.1. Модуль DrbObservable

module DRbObservable

 def add_observer(observer)

  @observer_peers ||= []

  unless observer.respond_to? :update

   raise NameError, "наблюдатель должен отвечать на вызов 'update'"

  end

  @observer_peers.push observer

 end

 def delete_observer(observer)

  @observer_peers.delete observer if defined? @observer_peers

 end

 def notify_observers(*arg)

  return unless defined? @observer_peers

  for i in @observer_peers.dup

   begin

    i.update(*arg)

   rescue

    delete_observer(i)

   end

  end

 end

end

Сервер (он же канал) в листинге 20.2 эмулирует биржевые котировки с помощью последовательности псевдослучайных чисел (простите мою иронию, но это очень точно соответствует характеру рынка). Символ, идентифицирующий компанию, — всего лишь косметическое украшение, никакого реального смысла в этой программе он не имеет. При каждом изменении цены посылается уведомление всем наблюдателям.

Листинг 20.2. Канал биржевых котировок (drb-сервер)

require "drb"

require "drb_pbserver"

# Генерировать случайные котировки.

class MockPrice

 MIN = 75

 RANGE = 50

 def initialize(symbol)

  @price = RANGE / 2

 end

 def price

  @price += (rand() - 0.5)*RANGE

  if @price < 0

   @price = -@price

  elsif @price >= RANGE

   @price = 2*RANGE - @price

  end

  MIN + @price

 end

end

class Ticker # Периодически получать котировку акций.

 include DRbObservable

 def initialize(price_feed)

  @feed = price_feed

  Thread.new { run }

 end

 def run

  lastPrice = nil

  loop do

   price = @feed.price

   print "Текущая котировка: #{price}\n"

   if price != lastPrice

    lastPrice = price

    notify_observers(Time.now, price)

   end

   sleep 1

  end

 end

end

ticker = Ticker.new(MockPrice.new("MSFT"))

DRb.start_service('druby://localhost:9001', ticker)

puts 'Нажмите [return] для завершения.'

gets

На платформе Windows примененный способ завершения программы вызывает сложности. Функция gets в этом случае может блокировать главный поток. Если вы это видите, попробуйте вместо обращения к gets поставить DRb.thread.join (а завершайте программу нажатием Ctrl+C).

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