今回はObserverパターン。とは言っても(本文中にもありますが)『観察』というよりは『通知』、Publish―Subscribeの関係になってます。そして相変わらず委譲を使ってます。
これも前回同様、Subject役をモデル、Observer役をコントローラまたはビューに当てはめるとMVCの典型的実装パターンですね。と思ってたら本でもちょこっとこのトピックに触れていました。
『更新のためのヒント情報の扱い』の節は私にとっていいヒントになりました。変化する情報に応じて一個ずつupdateメソッドを作るのでなく、メソッドはupdate一つにし、変化する情報を引数に入れるという方法は新鮮でした。
実行結果
1 * 4 **** 0 5 ***** 4 **** 10 ********** 3 *** ・ ・ ・
ソースコード
#!/usr/bin/env python # -*- coding: utf8 -*- class ConstructInterfaceError(Exception): def __init__(self): pass # Subject class NumberGenerator: _observers = [] def __init__(self): raise Exception("Abstract class") def addObserver(self, o): self._observers.append(o) def deleteObserver(self, o): self._observers.remove(o) def notifyObservers(self): for o in self._observers: o.update(self) def getNumber(self): raise NotImplementedError def execute(self): raise NotImplementedError # ConcreteSubject from random import randint class RandomNumberGenerator(NumberGenerator): def __init__(self, maxnumber): self.__maxnumber = maxnumber self.__number = 0 def getNumber(self): return self.__number def execute(self): self.__number = randint(0,self.__maxnumber) self.notifyObservers() # Observer interface class __Observer: def __init__(self): raise ConstructInterfaceError def update(self, subject): raise NotImplementedError # ConcreteObserver from time import sleep class DigitObserver(__Observer): def __init__(self): pass def update(self, subject): print subject.getNumber() sleep(0.5) # ConcreteObserver class GraphObserver(__Observer): def __init__(self): pass def update(self, subject): print ''.join(['*' for i in xrange(subject.getNumber())]) sleep(0.5) def main(): # NumberGenerator's instance g = RandomNumberGenerator(10) # Observer's instance do = DigitObserver() go = GraphObserver() g.addObserver(do) g.addObserver(go) for i in xrange(50): g.execute() if __name__=='__main__': main()