Chap1 Iterator Pattern
目的
- デザインパターンを学ぶために「Java言語で学ぶデザインパターン入門」を読んでいる
- 読んだだけでは頭に入らないため、プライベートで利用しているpython言語で各デザインパターンを実装して理解を深める
Iterator Patternとは
- for文で使われるループ変数(iなど)を抽象化し、一般化したデザインパターン
- 配列のように何かがたくさん集まっている時に、順番に指し示していくためのもの
繰り返し処理の例
#javaの場合
for(int i=0; i < arr.length; i++ ){
System.out.println(arr[i])
}
メリット
- Iterator(繰り返し処理)を利用する側がIteratorの実装に依存せずに逐次処理をできる
クラス図と説明
Iterator
- 反復処理を行う
- 要素を順番にスキャンしていくインタフェース
- has_nextメソッドが次の要素が存在するか確認を行う
- nextメソッドが次の要素を得る
Aggregate
- Iterator(反復役)を作り出すAPI
- iteratorメソッドが「要素を順番にスキャンしてくれる」役割をもつ
ConcretteIterator
- Iteratorインタフェースを実装する
- 自分が見ている位置(index)とスキャン対象の情報をもつ
Concrete Aggregate
- Aggreteインタフェースを実装したクラス
- 具体的なIterator(=ConcreteIterator)を作り出す
コード実装
- 書籍に準じて、本棚に対する逐次処理を見立てた逐次処理を実装した。
- ConcretaAggregateの役割をもつBookShelf(書庫)は複数のBookオブジェクトを持つように実装し、Bookオブジェクトの情報取り出しはBookクラスが務める
Aggregateインタフェース
- aggregate: 「集める」「集まる」「集合」の意味
- 抽象メソッドでiteratorメソッドをもつ
- 集合体に対応するIteratorを1個作成する
- 具象クラスはIteratorメソッドを使ってIteratorインターフェすを実装したクラスのインタフェースを作成する
- pythonで抽象クラスを描く場合はabcモジュールからABCMeta, abstractclassmethodをimportする
Aggregateインタフェース
from abc import ABCMeta, abstractclassmethod
#抽象クラス
class Iterator(metaclass=ABCMeta):
@abstractclassmethod
def iterator(self):
pass
Iteratorインタフェース
- ループ変数の役割をもち数え上げを行う
- has_nextメソッドは次の要素が存在するかチェックする抽象メソッド
- nextメソッドは集合体の要素を1個返す。返す時にループ変数を1つ前に進める
Iteratorインタフェース
class Iterator(metaclass=ABCMeta):
@abstractclassmethod
def has_next(self):
# 戻り値はBoolean
pass
@abstractclassmethod
def next(self):
# 戻り値はクラスインスタンス
pass
Bookクラス
- 書庫(BookShelf)に格納する1つのデータ
- pythonでクラスを作成した場合は基本的にpublicになる
- 擬似的にprivate変数を作成するためには__(アンダースコア2つ)をつける
Bookクラス
class Book():
"""
本を表すクラス
"""
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
BookShelfクラス
- Aggregateインターフェースを実装する
- 複数の本(Bookオブジェクト)を保持する
BookShelfクラス
class BookShelf(Aggregate):
def __init__(self, max_size):
"""
コンストラクタ
Parameters
----------
max_size: int
本棚に保管できる最大の数
"""
self._last = 0
self._books = []
def get_book_at(self,index):
"""
引数で受け取った場所に格納されている本を返す
Parameters
----------
index : int
本が格納されている場所(index)
Returns
-------
book : Book
本
"""
book = self._books[index]
return book
def append_book(self,book):
"""
本棚の最後に本を追加するメソッド
Parameters
----------
book : Book
追加する本
"""
self._books.append(book)
self._last = self._last+1
def get_length(self):
"""
格納されている本の数を取得する関数
Returns
-------
last : 格納されている本の数
"""
return self._last
def iterator(self):
"""
イテレータ
"""
return BookShelfIterator(self)
BookShelfIteratorクラス
- BookShelfクラスのスキャンを担当する
- Iteratorクラス(インターフェース)を実装し、nextメソッドおよびhas_nextメソッドの具体的な処理を記述する
- indexは現在の位置(本棚のどこの位置を指名しているか)
BookShelfIterator
class BookShelfIterator(Iterator):
"""
BookShelf(本棚)のスキャンを行うクラス
"""
def __init__(self, book_shelf):
self._index = 0
self._bookshelf= book_shelf
def has_next(self):
"""
本棚に本があるか操作を行う
"""
if(self._index < self._bookshelf.get_length()):
return True
else:
return False
def next(self):
"""
本棚の本を取り出す
"""
book = self._bookshelf.get_book_at(self._index)
self._index = self._index + 1
return book
サンプルプログラム(python版)
iterator.py
from abc import ABCMeta, abstractclassmethod
class Aggregate(metaclass=ABCMeta):
@abstractclassmethod
def iterator(self):
pass
class Iterator(metaclass=ABCMeta):
@abstractclassmethod
def has_next(self):
pass
@abstractclassmethod
def next(self):
pass
class BookShelfIterator(Iterator):
"""
BookShelf(本棚)のスキャンを行うクラス
"""
def __init__(self, book_shelf):
self._index = 0
self._bookshelf= book_shelf
def has_next(self):
"""
本棚に本があるか操作を行う
"""
if(self._index < self._bookshelf.get_length()):
return True
else:
return False
def next(self):
"""
本棚の本を取り出す
"""
book = self._bookshelf.get_book_at(self._index)
self._index = self._index + 1
return book
class Book():
"""
本を表すクラス
"""
def __init__(self, name):
self._name = name
def getName(self):
return self._name
class BookShelf(Aggregate):
def __init__(self, max_size):
"""
コンストラクタ
Parameters
----------
max_size: int
本棚に保管できる最大の数
"""
self._last = 0
self._books = []
def get_book_at(self,index):
"""
引数で受け取った場所に格納されている本を返す
Parameters
----------
index : int
本が格納されている場所(index)
Returns
-------
book : Book
本
"""
book = self._books[index]
return book
def append_book(self,book):
"""
本棚の最後に本を追加するメソッド
Parameters
----------
book : Book
追加する本
"""
self._books.append(book)
self._last = self._last+1
def get_length(self):
"""
格納されている本の数を取得する関数
Returns
-------
last : 格納されている本の数
"""
return self._last
def iterator(self):
"""
イテレータ
"""
return BookShelfIterator(self)
def main():
# 本棚を作成
book_shelf = BookShelf(4)
book_shelf.append_book(Book("Around the world"))
book_shelf.append_book(Book("Bible"))
book_shelf.append_book(Book("Cindelella"))
book_shelf.append_book(Book("Daddy-Long-Legs"))
#イテレータ作成
it = book_shelf.iterator()
while(it.has_next()):
book = it.next()
print(book.getName())
if __name__ == "__main__":
main()
所感
- listで宣言する場合はそこまで使う場面がないのではと思っている。
- クラスで実装する必要がある場面がありましたらご教示いただけると幸甚です。