酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

オブザーバー Ruby 2.0.0 デザインパターン速攻習得[Observer][Design Pattern]

GoFのデザインパターン(Design Pattern)のオブザーバー(Observer)のRubyコードを使った紹介記事です。

次の条件を満たす場合にオブザーバーパターンを使います。

* オブジェクトの状態が変化する可能性がある
* 変化したことを他のオブジェクトに通知する必要がある

例としては、Aで起きたイベントをB, Cが知る必要が有る場合などです。


オブザーバーとは?

あるオブジェクトの状態が変化した際に、そのオブジェクト自身が「観察者」に「通知」する仕組みです。オブザーバは以下の3つのオブジェクトによって構成されます。

サブジェクト(subject):変化する側のオブジェクト
オブザーバ(Observer):状態の変化を関連するオブジェクトに通知するインタフェース
具象オブザーバ(ConcreteObserver):状態の変化に関連して具体的な処理を行う

オブザーバのメリット

オブジェクト間の依存度を下げることができる
通知先の管理をオブザーバが行うことで、サブジェクトは通知側を意識しなくていい

サンプルソース

次のようなモデルを通してObserverデザインパターンを説明します。

Employee(サブジェクト):従業員を表す
Observable(オブザーバ):従業員のニュースを監視する仕組み(observer/Observable)
Payroll(具体オブザーバ1):給与の小切手の発行を行う
TaxMan(具体オブザーバ2):税金の請求書の発行を行う

まずは従業員を表すEmployeeクラスについてです。このEmployeeクラスは、name, title, salaryといったデータと、salaryの変更を受け付けるメソッドを持っています。

さらに、Employeeクラスにobservableをincludeします。observableはオブザーバーとしての機能を持ったrubyの標準モジュールです。

observableで用いるメソッドは次のとおりです。

  • add_observerメソッドで通知する先のオブジェクトを追加
  • changedメソッドとnotify_observersメソッドでオブジェクトに通知

こちらが、Employeeクラスの実装です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
require 'observer'
class Employee
  include Observable # Observerとして働く

  attr_reader :name, :title, :salary

  def initialize(name, title, salary)
    @name = name
    @title = title
    @salary = salary
    add_observer(Payroll.new)
    add_observer(TaxMan.new)
  end

  # 給与をセットして、ConcreteObserverに通知する
  def salary=(new_salary)
    @salary = new_salary
    changed
    notify_observers(self)
  end
end

次に給与の小切手の発行を行うPayrollクラスと、税金の請求書の発行を行うTaxManクラスを作成します。これらは具体オブザーバ(ConcreteObserver)にあたります。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 給与の小切手の発行を行う
class Payroll
  def update(changed_employee)
    puts "彼の給料は#{changed_employee.salary}になりました!#{changed_employee.title}のために新しい小切手を切ります。"
  end
end

# 税金の請求書の発行を行う
class TaxMan
  def update(changed_employee)
    puts "#{changed_employee.name}に新しい税金の請求書を送ります"
  end
end

コーディングは以上です。では結果を確認します。

1
2
3
4
5
6
7
john = Employee.new('John', 'Senior Vice President', 5000)
john.salary = 6000
#=> 彼の給料は6000になりました!Senior Vice Presidentのために新しい小切手を切ります。
#=> Johnに新しい税金の請求書を送ります
john.salary = 7000
#=> 彼の給料は7000になりました!Senior Vice Presidentのために新しい小切手を切ります。
#=> Johnに新しい税金の請求書を送ります

johnのsalary(給与)を変更するとObservableによってPayrollクラスと、TaxManクラスのupdateメソッドが連動して動いていることがわかります。

このサンプルソースはGitHubにも置いています。

サンプルソース(GitHub)

ストラテジーとの違い

オブザーバ:発生しているオブジェクトに対してイベントを通知している
ストラテジー:何らかの処理を行うためにオブジェクトを取得している

Special Thanks

Observer - Murayama Blog.

デザインパターン-Observer

17.Observer パターン

Amazon.co.jp: Rubyによるデザインパターン: Russ Olsen, ラス・オルセン, 小林 健一, 菅野 裕, 吉野 雅人, 山岸 夢人, 小島 努: 本

Special Thanks

@y_shindohさんにコードのタイポを指摘して頂きました。 ご丁寧に間違っていた部分のdiffを作って頂けたお陰ですぐに修正出来ました。有難うございます^^

変更来歴

12/12/10 09:00 GitHubへのサンプルソースの設置。導入文の修正
12/12/11 00:00 書籍へのリンクをAmazon アフィリエイトに変更
12/12/15 23:30 ソースコードに説明を追加
13/06/20 17:40 Ruby2.0.0対応、読みづらい部分を修正
15/01/16 20:50 タイポの修正

おすすめの書籍