RubyでObserver
”Rubyによるデザインパターン”
名前の通りRubyでデザインパターンを学習する本でAmazonでも評価が高い。
GofのパターンをModuleやブロックなどRubyで書いたらどうなるか書いてあり他言語からRubyに来た人にオススメです。
Observerの章でModuleを使った実装が参考になったのでメモのついでにブログに書いておく。Observerパターンを説明するときは、エクセルがいい例になる。
エクセルの機能で、表のAとBのマスに数字を入力した瞬間にAとBの合計の値がCに表示される。
AとBに変更があったらCに"変更しましたよ"とメッセージを伝え、Cは通知を受け取ると、AとBの合計の数値を出力してやる。
ちなみにAとかBのことをセルという。セルの数値をグラフ化することもでき、リアルタイムでグラフが変化する。つまりAやBの数値を変更するとグラフの棒グラフも縦に伸びたり、縮んだりする。
よくあるのがCellコンストラクタにGraphインスタンスを渡して変更があったらCellクラス内でGraph.updateメソッドを呼び出す形。
class Cell attr_accessor :graph def initialize (graph) @graph = graph @A = 0; @B = 0; end def A=(num) @A = num @graph.update(@A,@B) end def B=(num) @B = num @graph.update(@A,@B) end end class Graph def update(_A,_B) if _A > 0 && _B > 0 then (_A + _B).times do print "◼︎" end puts end end end cell = Cell.new(Graph.new) cell.A = 4 cell.B = 4 #◼︎◼︎◼︎◼︎◼︎◼︎◼︎ cell.B = 10 #◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎
RubyならModuleとブロックを使おう。
Observerの部分をモジュールベースにすれば、再利用しやすい。また登録や削除なんかができたらいい。ブロックベースだと条件式が使えていいかも。
module Subject def initialize @observers = [] end def add_observer( &observer ) @observers << observer end def delete_observer(observer) observers.delete(observer) end def notify_observers @observers.each do |observer| observer.call(self) end end end class Cell include Subject def initialize () super() @A = 0; @B = 0; end def A=(num) @A = num notify_observers end def A @A end def B=(num) @B = num notify_observers end def B @B end end class Graph def update(_A,_B) if _A > 0 && _B > 0 then (_A + _B).times do print "◼︎" end puts end end end class Mail def send puts "メール送信" end end graph = Graph.new mail = Mail.new cell = Cell.new cell.add_observer do |obj| graph.update(obj.A, obj.B) end cell.add_observer do |obj| sum = obj.A + obj.B (sum > 10) && mail.send end cell.A = 2 cell.B = 2 #◼︎◼︎◼︎◼︎ cell.B = 10 #◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎ #メール送信