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と