Observerパターンについて(デザインパターン)

【結論】

・Observerパターンとは、デザインパターンの一つで、状態変化に応じた処理を記述する時に有効な実装手法

・ObserverがSubjectから状態変化の通知を受け取り、それをトリガーに処理を実行する

・クラス間の依存度を下げるメリットがあるが、連鎖的に他のObserverの処理も走る場合、ロジックが散らばって見通しが悪くなるデメリットもある

【目次】

【本題】

Observerパターンについて

Observerパターンとは、デザインパターンの一つで、状態変化に応じた処理を記述する時に有効な実装手法です。

実装方法としては、クラスを以下の役割に分割して実装を行います。

サブジェクト(subject):変化する側のオブジェクト

・オブザーバ(Observer):状態の変化を関連するオブジェクトに通知するインタフェース

・具象オブザーバ(ConcreteObserver):状態の変化に関連して具体的な処理を行う

ObserverがSubjectから状態変化の通知を受け取り、それをトリガーに処理を実行する流れになります。

サンプルコード

以下の様な条件でサンプルコードを作成しました。

  • 商品の価格を管理するプログラム
  • 商品には割引率が設定できる(デフォルト0%)
  • 割引率が変更になった時、変更後の価格を表示するのと、メールを飛ばす二つの処理を行う
class PriceList
  def update(changed_item)
    puts "商品名:#{changed_item.name} | 金額:#{changed_item.display_price}"
  end
end

class SendMail
  def update(changed_item)
    puts "商品「#{changed_item.name} 」の 金額が「#{changed_item.display_price}円」に変更されました"
  end
end

class Item
  attr_reader :name, :price, :category

  def initialize(name, price, category)
    @name = name
    @price = price
    @discount_rate = 0.0
    @category = category
    @observers = []
  end

  def show
    puts "商品名:#{name} | 金額:#{price}"
  end

  def display_price
    @price - (@price * @discount_rate)
  end

  def add_observer(observer)
    @observers << observer
  end

  def price_down!(new_rate)
    @discount_rate = new_rate
    notify_observers
  end

  private

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

item = Item.new('ラムネ', 100, 'お菓子')
item.show

pricelist = PriceList.new
item.add_observer(pricelist)
sendmail = SendMail.new
item.add_observer(sendmail)

item.price_down!(0.5)

実行結果

商品名:ラムネ | 金額:100円
商品名:ラムネ | 金額:50.0
商品「ラムネ 」の 金額が「50.0円」に変更されました

@observersという配列に、オブザーバを格納しています。

サブジェクトであるItemクラスに状態変化(価格変更)があれば、それを配列に格納していたオブザーバーに通知して、それぞれの処理を実行します。

price_down!メソッドからnotify_observersメソッドを呼び出すことによって通知を制御しています。

メリットとデメリット

クラス間の依存度を下げるメリットがありますが、オブザーバーに他のオブザーバーが数珠つなぎの様に繋がっていて、連鎖的に処理も走る場合、ロジックが散らばって見通しが悪くなるデメリットもあります。

部分的に適用すると、混乱を招く恐れがあるので、実装する際は、全体的な設計と相談すべきだと考えられます。

MVCモデルとの関係性

Observer パターンは、MVC(Model 、View 、Controller) アーキテクチャとともに説明されることがよくあります。

Model は、表示形式に依存しないデータを保持するオブジェクトで、View が表示を制御する情報を持っています。

参考情報

オブザーバ(Observer) | Ruby デザインパターン | 酒と涙とRubyとRailsと

事例で学ぶデザインパターン 第 5 回 | オブジェクトの広場

Rubyデザインパターン 3日目 : Observer - Qiita