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

f:id:ryoutaku_jo:20190726035256p:plain

【結論】

・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

《今日の学習進捗(3年以内に10000時間に向けて)》

トライアルで行われているデザインパターンの社内勉強会に初めて参加した。

Observerパターンが題材だったが、デメリットはあるものの実業務でも適用できる余地がある内容だったのと、CTOの解説が分かりやすかったので、非常にイメージしやすかった。

しかし、いざ問題を出されてコードを書くとなった時、手が動かず制限時間内に完成させる事が出来なかった。事前に概要は予習していたが、コーディングの経験がまだまだ浅い自分が、いきなり取り組むにはハードルが高かった。

他の人のコードを読んでも勉強になったが、CTOからのレビューを受けられなかったのは非常に勿体なかった・・・次回はサンプルコードを書くところまで予習の時点で行なって対応したい。

デザインパターン自体は、実務でそのまま転用できる機会は少ないかもしれないが、それを題材に設計/実装を手を動かして繰り返し行えば、設計力の向上が期待できると感じた。今後も定期的に行われるのであれば、その機会を有効に活用して行きたい。

学習開始からの期間 :230日
今日までの合計時間:2217h
一日あたりの平均学習時間:9.7h
今日までに到達すべき目標時間:2100h
目標との解離:117h
「10,000時間」まで、

残り・・・「7783時間!」