読者です 読者をやめる 読者になる 読者になる

WEB系エンジニアの勉強日記

Baby steps to Giant strides!

Observer Pattern - Design Pattern i Ruby Chapter 5

注意点

  • 更新頻度を考える。 考えなしにすべての変更時にobserverオブジェクトに通知すると、かなりの数の冗長な通知が飛び交ってしまう可能性がある。 どういったタミングで通知を行うかの戦略は考えておくべき。

  • 変更の一貫性 上記の高新頻度にも似ているが、細かい情報の変更を全て通知していると、整合性が取れなくなるケースが考えられる。 どういった変更のまとまりで通知するかを考えておく必要がある。

バリエーション

ruby標準のobserver

module Observable (Ruby 1.8.7)

updateメソッドを実装したobserverオブジェクトを定義することで簡単に実装できる。


コードベースのobserver

observerオブジェクトにupdateメソッドを実装したクラスのオブジェクトではなく、Procオブジェクトを使うことで、より簡単にObserverオブジェクトを登録できる。


updateメソッドの引数

一番簡単な実装はシンプルにselfを渡す実装だけど、この場合はobserverがobservableオブジェクトの内容から変更箇所を特定するような処理が必要になったりする。

こういったことが問題になるようなケースでは、変更箇所ごとに細かいupdate_***系のメソッドを用意するといい。

ただこの場合だと標準のobserverモジュールが使えないため、自分でmoduleを定義する必要がある。

実践

NewsFeedの通知を受け取るような想定で実装

require 'observer'

class NewsFeed
  include Observable
  def initialize
    @news = []
    @next_news_id = 1
  end

  def add_news(title)
    @news << {
      id: @next_news_id,
      title: title
    }
    @next_news_id += 1
    changed
  end

  def publish
    notify_observers self
  end

  def getNewsAfter(id)
    @news.select {|news| news[:id] > id}
  end
end

class NewsListener
  def initialize
    @last_received_news_id = 0
  end

  def update(news_feed)
    unread = news_feed.getNewsAfter @last_received_news_id
    @last_received_news_id = unread.last[:id]
    p unread
  end
end

news_feed = NewsFeed.new
news_feed.add_observer NewsListener.new

news_feed.add_news 'news1'
news_feed.publish

news_feed.add_news 'news2'
news_feed.add_news 'news3'
news_feed.publish