Edited at

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

More than 1 year has passed since last update.


参考

@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パターン:コンテキストが、何か特定の処理を行うためにストラテジを呼び出す