LoginSignup
32
29

More than 5 years have passed since last update.

Pythonによるデザインパターン【Observer】-本日のニュースをお届けします-

Last updated at Posted at 2018-01-25

参考

@kidachi1さんの記事のRubyの記事のソースコードをpythonに書き換えてます。
https://qiita.com/kidach1/items/ce18d2a926c558159689
@kidachi1さん、いつもありがとうございます。

概要

Rubyによるデザインパターン第5章。
Observer Pattern。

Rubyによるデザインパターン5原則に則って理解する。
この記事はPython

どんなパターンか

あるオブジェクトの状態に関心のあるオブジェクトに、都度通知を送る。

ニュースの発信源(Subject)とニュースの消費者(Observer)間に綺麗なインターフェイスを用意する。

Subject

あるニュースを配信するクラス

Observer

あるニュースを得ることに関心があるクラス

メリット

ニュースの発信者と受信者の間の依存関係を排除する。

問題のあるコード

従業員の給与の変化を経理部門に伝えるシステム

従業員クラス

class Employee:
  def __init__(self, name, title, salary, payroll):
    self.name = name
    self.title = title
    self.salary = salary
    self.payroll = payroll

  def update_salary(self, new_salary):
    self.salary = new_salary
    self.payroll.update(self)

経理部門クラス

class Payroll:
  def __init__(self):
    pass
  def update(self, changed_employee):  # Subjectオブジェクトを受け取る
    print ( changed_employee.name + "の給料が" + str(changed_employee.salary) + "ドルに上がりました!" )    

クラスの利用

payroll = Payroll()
employee = Employee( "tsuji","leader", 1000, payroll  )
employee.update_salary(2000)

#tsujiの給料が2000ドルに上がりました!

問題

もし経理部門以外にも通知したくなったら?

→今はEmployeeクラスに手を入れる必要がある。
本質的にはEmployeeに対する変更など何もないにも関わらず・・。

そこで、

変化する事項(「従業員の給与の変更」というニュースを誰が受け取るか)を、Employeeオブジェクトから分離する。
→必要なのは、Employeeオブジェクトの変化に関心のあるオブジェクトの一覧。

従業員クラス

class Employee2:
  def __init__(self, name, title, salary ):
    self.name = name
    self.title = title
    self.salary = salary
    self.observers = []

  def add_observer(self, observer):
    self.observers.append(observer) 

  def update_salary(self, new_salary):
    self.salary = new_salary
    self.notify_observers()

  def notify_observers(self):
    for  observer  in  self.observers :
      observer.update(self)

経理部クラス

class Payroll:
  def __init__(self):
    pass
  def update(self, changed_employee):  # Subjectオブジェクトを受け取る
    print ( changed_employee.name + "の給料が" + str(changed_employee.salary) + "ドルに上がりました!" )    
    print ( "経理部門は" + changed_employee.name + "に小切手を切ります!")    

税務署員クラス

class Taxman:
  def __init__(self):
    pass
  def update(self, changed_employee):  # Subjectオブジェクトを受け取る
    print ( changed_employee.name + "の給料が" + str(changed_employee.salary) + "ドルに上がりました!" )    
    print ( "税務署員は" + changed_employee.name + "に新しい税金請求書を送ります!") 

クラスの利用


taxman = Taxman()
payroll = Payroll()
employee2 = Employee2("daisuke","member", 3000)

employee2.add_observer(payroll)
employee2.add_observer(taxman)

employee2.update_salary(4000)

まとめ

変わるもの(オブザーバー)と変わらないもの(サブジェクト)を分離して、変化に強い構造へ

Strategyパターンとの比較

形は似ている

Observerパターン:サブジェクトがオブザーバーを呼び出す
Strategyパターン:コンテキストがストラテジを呼び出す

違いは目的

Observerパターン:サブジェクトで発生したイベントをオブザーバーへ通知する
Strategyパターン:コンテキストが、何か特定の処理を行うためにストラテジを呼び出す

32
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
29