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

さまよえる、Android

Androidのプログラミングで便利なことや残しておきたいことを残しておく。もしオススメのライブラリがあったら教えてくださいね。

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 #◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎
#メール送信