感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

【GoFデザインパターン】Observerパターン

<スポンサーリンク>

Observerパターンの定義

Observerパターンは、オブジェクトの振る舞いに注目したパターンで、オブジェクトの変化を他のオブジェクトに通知することを目的としている。
GoFでは以下のように定義される。

あるオブジェクトが状態を変えたときに、それに依存するすべてのオブジェクトに自動的にそのことが知らされ、また、それらが更新されるように、オブジェクト間に一対多の依存関係を定義する。

Observerパターンってなんで必要なの?

オブジェクト同士をゆるく結合したまま、強調操作をさせることができる。ConcreteSubjectクラスとConcreteObserverクラスの間に直接の関係がなくなり、両クラスの関係はSubjectとObserverという、両者の親となるクラスで定義される。
なので、ConcreteSubjectとConcreteObserverは独立して修正・拡張することができる。
新しいConcreteObserverクラスを追加する場合も、SubjectクラスやConcreteSubjectクラスを修正する必要はない。

Observerパターンのクラス図

Observerパターンの登場人物

・Subjectの役
Subjectは観察される側を表す。
状態が変化するのも観察される側である。
観察者となるObserver役を登録/削除するメソッドを持つ。
Observerクラスで定義されたAPIを通じて、ConcreteObserverクラスで実装されている具体的な処理を呼び出す。

・ConcreteSubject役
ConcreteSubject役は、具体的な観察される側を表現する。

・Observer役
Subjectから「状態が変化したよ」と教えてもらう役のこと。
観測クラス。通知を受け取るためのAPIを定義する。そのAPI(メソッド)がupdate。
ListenerとかHandlerとも呼ばれる。

・ConcreteObserverの役
具体的なObserverで、updateメソッドが呼び出されたときに、そのupdateメソッドの中でSubject役の現在の状態を取得する。

サンプル

Rubyデザパタ本をちょっとアレンジしてみた。

class Payroll
  attr_accessor :name
  def initialize(name)
    @name = name
  end
  def update( changed_employee)
    puts("私は#{name}です")
    puts("#{changed_employee.name}のために小切手を切ります")
    puts("彼の給料はいま#{changed_employee.salary}です!")
  end
end

class Employee
  attr_reader :name
  attr_accessor :title, :salary

  def initialize( name, title, salary)
    @name = name
    @titel = title
    @salary = salary
    @observers = []
  end

  def salary=(new_salary)
    @salary = new_salary

    notify_observers
  end

  def notify_observers
    @observers.each do |observer|
      observer.update(self)
    end
  end

  def add_observer(observer)
    @observers << observer
  end

  def delete_observer(observer)
    @observers.delete(observer)
  end

end

payroll = Payroll.new("hoge")
fred = Employee.new('Fred','Crane Operator',payroll)

fred.add_observer(payroll)
fred.salary = 35000

puts("")
puts("--オブザーバーを追加--")
yajiuma = Payroll.new("yajiuma")
fred.add_observer(yajiuma)
fred.salary = 55000

puts("")
puts("--さらにオブザーバーを追加--")
sho322 = Payroll.new("sho322")
fred.add_observer(sho322)
fred.salary = 60000
#payroll.update(fred)

要は、変更したものと、変更を通知されるものの結合を疎にできることが、オブザーバーパターンの肝だ。
上記の例では、

fred.salary = 60000

とやれば、自動的にobserver達に通知される。
Subject側は、どんなobserverがぶら下がっているのかも意識しなくてもいい。
勝手に変更すれば、observerが勝手に受け取ってくれる。
上記の結果はこうなる。

私はhogeです
Fredのために小切手を切ります
彼の給料はいま35000です!

--オブザーバーを追加--
私はhogeです
Fredのために小切手を切ります
彼の給料はいま55000です!
私はyajiumaです
Fredのために小切手を切ります
彼の給料はいま55000です!

--さらにオブザーバーを追加--
私はhogeです
Fredのために小切手を切ります
彼の給料はいま60000です!
私はyajiumaです
Fredのために小切手を切ります
彼の給料はいま60000です!
私はsho322です
Fredのために小切手を切ります
彼の給料はいま60000です!

最後に、Rubyの標準ライブラリにはObservalbeモジュールがあるので、それを利用してObserverパターンを適用するのが一般的なようだ。

読んだ本

Rubyによるデザインパターン

Rubyによるデザインパターン


Ruby唯一のGoFデザインパターン本。

感謝のプログラミング

今回で感謝のプログラミングは【625時間目】
10000時間まで、あと【9375時間】