Паттерн программирования Observer в Ruby

октября 2, 2011  |  Published in Ruby, STDLIB  |  2 Comments

Патерн Observer относится к семейству publish/subscribe паттернов программирования. Observer предоставляет механизм для уведомления одним объектом другого при изменении собственного состояния. Объект, который сообщает об изменении своего состояния называется уведомителем или наблюдаемым объектом, а объекты, которые уведомляются об изменении состояния уведомителя называются подписчиками или наблюдателями.

В стандартной библиотеке Ruby имеется отличная реализация данного паттерна — библиотека Observer.

Давайте напишем простой код, в котором покажем как можно использовать паттерн Observer.

Допустим у нас имеется объект — product со свойством price и несколько объектов customer’ов. Задача заключается в том, чтобы все объекты типа Customer следили за ценой и в зависимости от изменения цены покупали товар.

require 'observer'

class Product
  include Observable

  def initialize
    @price = 100
  end
  def set_price
    @old_price = @price
    @price = 50 + rand(50)
    unless @price == @old_price
      changed
      notify_observers(@price)
    end
  end
end

class Customer
  def initialize(name, good_price)
    @customer   = name
    @good_price = good_price
  end
  def update(price)
    unless price > @good_price
      puts @customer + " buy product for " + price.to_s + " dollars."
    end
  end
end

product = Product.new

ivan  = Customer.new("Ivan", 70)
vasya = Customer.new("Vasya", 80)
vova  = Customer.new("Vova", 90)

product.add_observer ivan
product.add_observer vasya
product.add_observer vova

10.times do
  product.set_price
  puts product.price
end

В класс Product подмешиваются методы из модуля Observable. Сперва мы рассмотрим те, что встречались нам в коде:

#add_observer — метод добавляет подписчика

#notify_observers — метод передает вызывает метод #update объекта — наблюдателя и может передавать в него некоторые значения.

#changed — устанавливает состояние объекта в «измененное». Без вызова этого метода подписчики не получат сообщения об изменениях.

#changed? — проверяет состояние объекта-уведомителя.

#count_observers — метод возвращает количество подписчиков.

#delete_observer — метод удаляет у объекта-уведомителя переданный в качестве аргумента подписчик.

#delete_observers — удаляет все подписчики.

Для класса подписчиков можно сделать небольшой рефакторинг:

class Customer
  def initialize(name, good_price, publisher)
    @customer   = name
    @good_price = good_price
    publisher.add_observer self
  end
  def update(price)
    unless price > @good_price
      puts @customer + " buy product for " + price.to_s + " dollars."
    end
  end
end

product = Product.new

ivan  = Customer.new("Ivan", 70, product)
vasya = Customer.new("Vasya", 80, product)
vova  = Customer.new("Vova", 90, product)

Так уже лучше.

Внимание! Соревнование!
Необходимо написать собственное решение паттерна Observer. Не нужно углубляться в суть паттерна, просто пишите то, каким вы его видите. Можете добавить туда различные плюшки, какие пожелаете. Код присылайте мне на почту egotraumatic[dog]gmail.com. Когда насобирается несколько реализаций, я обо всех напишу обзорную статью и вместе с читателями блога выберем самое хорошее решение.

Tags: , , , ,

Responses

  1. mearion says:

    октября 2, 2011 at 19:17 (#)

    Сперма?!

  2. mearion says:

    октября 2, 2011 at 19:23 (#)

    Ну а если серьезно, вся сила observer, конечно, проявляется при создание Sweepers для обновления кэша. Например

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.