Программирование на языке Ruby - [227]

Шрифт
Интервал

.

Это, конечно, не все, что можно сказать о библиотеке >drb. Но для обзора вполне достаточно. В следующем разделе мы рассмотрим простой drb-сервер и drb-клиент, близкие к реальным программам. А затем поговорим о программах Rinda и Ring.

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) начинает с установления соединения с сервером. Он получает ссылку на объект показа котировок и устанавливает верхний и нижний пороги изменения цены. Затем клиент выводит сообщение пользователю всякий раз, как цена выходит за пределы указанного диапазона.

Листинг 20.3. Наблюдатель биржевых котировок (drb-клиент)

>require "drb"


>class Warner

> include DRbUndumped


> def initialize(ticker, limit)

>  @limit = limit

>  ticker.add_observer(self) # Любой объект Warner

>                            # является наблюдателем.

> end

>end


>class WarnLow < Warner

> def update(time, price)    # Обратный вызов наблюдателя.

>  if price < @limit

>   print "--- #{time.to_s}: Цена ниже #@limit: #{price}\n"

>  end

> end

>end


>class WarnHigh < Warner

> def update(time, price)    # Обратный вызов наблюдателя.

>  if price > @limit

>   print "+++ #{time.to_s}: Цена выше #@limit: #{price}\n"

>  end

> end

>end


>DRb.start_service

>ticker = DRbObject.new(nil, "druby://localhost:9001")


>WarnLow.new(ticker, 90)

>WarnHigh.new(ticker, 110)

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

>gets

Модуль >DRbUndumped (см. листинге 20.3) следует включать в любой объект, который не нужно подвергать маршалингу. Самого присутствия этого модуля в числе предков объекта достаточно, чтобы >drb не пытался применять к нему маршалинг. Вот исходный текст этого модуля целиком:

>module DrbUndumped

>def _dump(dummy)

>raise TypeError, "can't dump"

>end

>end

Приложение из этого раздела достаточно содержательно, и в то же время в нем легко разобраться. Есть и другие подходы к решению подобных задач. Но способ, показанный нами, демонстрирует простоту и элегантность распределенного Ruby.

20.3. Rinda: пространство кортежей в Ruby

Термин «пространство кортежей» появился в 1985 году, а сама идея еще старше. Кортежем называется массив или вектор, состоящий из элементов данных (как строка в таблице базы данных).


Рекомендуем почитать
Графика DirectX в Delphi

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Вторая жизнь старых компьютеров

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


DirectX 8. Начинаем работу с DirectX Graphics

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Симуляция частичной специализации

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Обработка событий в С++

В книге рассказывается история главного героя, который сталкивается с различными проблемами и препятствиями на протяжении всего своего путешествия. По пути он встречает множество второстепенных персонажей, которые играют важные роли в истории. Благодаря опыту главного героя книга исследует такие темы, как любовь, потеря, надежда и стойкость. По мере того, как главный герой преодолевает свои трудности, он усваивает ценные уроки жизни и растет как личность.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.