今回は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()
0 件のコメント:
コメントを投稿