2010年11月28日日曜日

第17章 Observerパターン : 状態の変化を通知する



今回は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 件のコメント:

コメントを投稿