2010年11月10日水曜日

第1章 Iteratorパターン : 一つ一つ数え上げる



これは分かりやすかった。引っ掛かったところは
  • IteratorはAggregate(集合体)があって初めて意味を持つので、その集合体にIteratorを作成するメソッドを持たせる
  • next()は現在のインデックスの値を返す
  • hasNext()はnext()が呼べるかどうかという真偽値を返す
といったところ。


応用1 ― pythonで実装

練習問題をやってもいいのだけど、ここのところpythonを使う機会が多いのでpythonでIteratorパターンを書いてみようと思います。
教本と同じBookshelfを実装してみるとこんな感じになりました。
#!/usr/bin/env python

class __Aggregator:
    def __init__(self): raise Exception('abstract class')
    def iterator(self): raise Exception('iterator() must be implemented')

class __Iterator:
    def __init__(self): raise Exception('abstract class')
    def next(self): raise Exception('next() must be implemented')
    def hasNext(self): raise Exception('hasNext() must be implemented')

class Bookshelf(__Aggregator):
    def __init__(self): self.__books = []
    def getBookAt(self, index): return self.__books[index]
    def appendBook(self, book): self.__books.append(book)
    def getLength(self): return len(self.__books)
    def iterator(self): return BookshelfIterator(self)

class Book:
    def __init__(self, name): self.__name = name
    def getName(self): return self.__name

class BookshelfIterator(__Iterator):
    def __init__(self, bookshelf):
        self.__bookshelf = bookshelf
        self.__index = 0

    def next(self):
        book = self.__bookshelf.getBookAt(self.__index)
        self.__index += 1
        return book

    def hasNext(self): return self.__index < self.__bookshelf.getLength()

def main():
    bookshelf = Bookshelf()
    bookshelf.appendBook(Book("Around the World in 80 Days"))
    bookshelf.appendBook(Book("Bible"))
    bookshelf.appendBook(Book("Cinderella"))
    bookshelf.appendBook(Book("Daddy-Long-Legs"))
    it = bookshelf.iterator()
    while it.hasNext():
        print it.next().getName()

if __name__=='__main__': main()

pythonにはJavaでいうインターフェイスや抽象クラスの概念はないので、アンダースコアを2つつけて明示化してあります。それ以外は何の変哲もなし。実行結果も同じ。


応用2 ― もっと簡単なpythonでの実装

調べてみると、pythonにはイテレータを実装する仕組みが既にあった。
http://www.python.jp/doc/2.5/tut/node11.html#SECTION0011800000000000000000
(というかあったけどあえて自分で書いてた。勉強ですからね)
前のとの違いは
  • hasNext()は無くて、next()を呼んだときに値がなければ例外StopIterationを投げる
  • 利用側がnext()を直接呼ばない。代わりにfor loopを使う
#!/usr/bin/env python

class __Aggregator:
    def __init__(self): raise Exception('abstract class')
    def iterator(self): raise Exception('iterator() must be implemented')

class Bookshelf(__Aggregator):
    def __init__(self): self.__books = []
    def getBookAt(self, index): return self.__books[index]
    def appendBook(self, book): self.__books.append(book)
    def getLength(self): return len(self.__books)
    def iterator(self): return BookshelfIterator(self)

class Book:
    def __init__(self, name): self.__name = name
    def getName(self): return self.__name

class BookshelfIterator():
    def __init__(self, bookshelf):
        self.__bookshelf = bookshelf
        self.__index = 0

    # 以下の2関数を実装することがIteratorを実装することと等価
    def __iter__(self): return self
    def next(self):
        if self.__index >= self.__bookshelf.getLength(): raise StopIteration
        book = self.__bookshelf.getBookAt(self.__index)
        self.__index += 1
        return book


def main():
    bookshelf = Bookshelf()
    bookshelf.appendBook(Book("Around the World in 80 Days"))
    bookshelf.appendBook(Book("Bible"))
    bookshelf.appendBook(Book("Cinderella"))
    bookshelf.appendBook(Book("Daddy-Long-Legs"))
    it = bookshelf.iterator()
    for b in it: print b.getName()

if __name__=='__main__': main()
ごちそうさまでした。

0 件のコメント:

コメントを投稿