「データの更新を複数のオブジェクト(オブザーバ)に通知する」パターンです。
「データの更新」と「その他処理」の責任を分離することで、ソースコードの柔軟性を増します。
Railsなどで使用されている「MVC(モデル・ビュー・コントローラー)」もこのパターンの一種です。
数字を変更したときに、
の2つの画面を同時に変更することを考えます。
(「グラフとして表示」は数字の大きさの分米印をつけることで対応します。)
def main():
m = ConcreteModel()
m.add_observer(NumView())
m.add_observer(ExcelView())
for i in [5, 10, 15]:
m.num = i
# Subject
class Model:
def __init__(self):
self.__observers = []
self.__num = None
def add_observer(self, observer):
self.__observers.append(observer)
def notify_observer(self):
for observer in self.__observers:
observer.update(self)
# ConcreteSubject
class ConcreteModel(Model):
def __init__(self):
super().__init__()
@property
def num(self):
return self.__num
@num.setter
def num(self, num):
self.__num = num
self.notify_observer() # important point
class Observer:
def __init__(self):
pass
def update():
pass
# ConcreteObserver1
class NumView(Observer):
def __init__(self):
pass
# ここも大事
def update(self, model):
s = "NView: {}".format(model.num)
print(s)
# ConcreteObserver2
class ExcelView(Observer):
def __init__(self):
pass
# ここも大事
def update(self, model):
s = "EView: {}".format("*" * model.num)
print(s)
if __name__ == "__main__":
main()
「データの更新」の処理と「表示」の処理を切り分けることが目的です。
データ更新を担う側から見ると、このようになっています。
class ConcreteModel(Model):
...
# 実際はModelクラスにある
def notify_observer(self):
for observer in self.__observers:
observer.update(self)
@num.setter
def num(self, num):
self.__num = num
self.notify_observer() # important point
データ更新を担う側から見ると、データ更新される側のupdateを起動するだけです。
詳細な処理は(Concrete)Model側は知りません。
データ更新される側から見ると、このようになっています。
class ExcelView(Observer):
...
def update(self, model):
s = "EView: {}".format("*" * model.num)
print(s)
Observerを継承し、updateメソッドを実装すると、
データ更新する側から更新されたデータが届きます。
データ更新される側はデータが来たら処理をする、という処理のみを実装すればOKです。
特になし
実践Python3(例題をお借りしました)