pythonによるデザインパターン[Iteratory]
# Intro
この文章は結城 浩さんの「Java言語で学ぶデザインパターン入門」を、pythonで実装してみたサンプルコードです。
筆者の環境は以下の通りです。Python 3.6.3
まだ修行中の身なので間違いがあると思いますがご了承ください。 今回は「Iterator」です。
# Summarise
本書のp2によると、 Iteratorとは
何かがたくさん集まっているときに、それを順番に指し示していき、全体をスキャンしていく処理を行うためのもの
とあります。要は繰り返し構文ですね。
pythonに限らず、(モダンな)ほどんどの言語は for
や yeild
や append
などの構文がサポートしてあり、わざわざこのデザインパターンを使わなくても内部実装として用意してあります。ですが、内部実装を確認するためにもiteratorの実装を確かめてみましょう。
# Practice
## Specification
本棚を示すプログラムを作成します。
本棚は class BookShelf
として表し、本は class Book
として表現します。本棚に、 name
Filed(本の名前)を設定したclass Book
を追加していきます。
最後に本棚から本を取り出していって、 name
Filed(本の名前)を標準出力します。絶対に for
や append
を使ってはいけません(自前で実装しましょう)。
## Explanation
まず本を表す class Book
を作成します。
ただname
Filed(本の名前)を設定しているだけなので説明は省きます。
次に本棚を表す class BookShelf
を作成します。
__books
Fieldに class Book
のインスタンスのListを代入し、__last
Fieldに格納されている本の数を代入します。それらのFieldをうまく利用して、
- indexの本を取得
def get_book_at
- 本を追加
def append_book
- 本の数を取得
def get_length
を実装しています。細かい実装は読めばわかると思うので説明は省きます。それよりも def iterator
が重要なのですが便宜上、次に説明します。
次に本棚の数え上げの管理を行う class BookShelfIterator
を作成します。
__book_shelf
Fieldに class BookShelf
のインスタンスのを代入し、__index
Fieldに参照している本のインデックスを代入します。
def has_next
では次の本が存在するか確認します。もし__index
Fieldが class BookShelf
の def get_length
より小さければ、すなわち現在参照している本のインデックスが本棚にある本の数より小さければ、Trueを返します。それ以外、つまり現在参照している本のインデックスが本棚にある本の数以上ならFalseを返します。
また、 def next
では次の本を返します。__book_shelf
Fieldから def get_book_at(self.__index)
を用いて、現在参照しているインデックスの本を取得します。その後参照しているインデックスを1つ増やし、本を返します。
以上の処理によって、ループや数え上げが実現できます。
このように本棚class BookShelf
と本棚の数え上げの管理class BookShelfIterator
とを分けて実装することで、再利用化がしやすくなっています。
最後にmain関数をみてみましょう。
class BookShelf
のインスタンスを作成し、 def append_book
で本(class Book
)をどんどん追加していきます。重要なのが以下の def iterator
です。
it = book_shelf.iterator()
これによって、先程作った本棚(class BookShelf
)に関するclass BookShelfIterator
のインスタンスを作成することができます。このitを用いることで、 def has_next()
と def next()
を使うことができ、ループが実現します。
## Sample Code
サンプルコードでは抽象クラス class Aggregation
と class Iterator
が追加されていますが、これは本棚以外のものにも、数え上げを実装する時ためのクラスです。今回は本棚の具体例を説明するだけで事足りるので、説明は省きます。
python3 iterator.py Aroun d the World in 80 days
Bible
Cinderella
Daddy-Long-Legs
ちなみにpythonが本気を出すと下のようにかけます🐍🐍🐍 ( def __itr__
を定義すると、 def __next__
がループが走るときに呼ばれます。詳しくはコチラ)
# Conclusion
まあ、ざっとみていきましたが最初に述べたように、現在のほとんどの言語は言語機能としてIteratorを実装しているので、サッと確認するだけで良さそうです。ですが、pythonのIteratorは結構色々な機能を持っているので、一度確認しておくことをお勧めします。
# ref
- 「増補改訂版 Java言語で学ぶデザインパターン入門」 結城浩(著)第11版
- 「9. Classes — Python 3.6.4 documentation」
https://docs.python.org/3/tutorial/classes.html#iterators