pythonによるデザインパターン[Iteratory]

# Intro

この文章は結城 浩さんの「Java言語で学ぶデザインパターン入門」を、pythonで実装してみたサンプルコードです。

筆者の環境は以下の通りです。Python 3.6.3

まだ修行中の身なので間違いがあると思いますがご了承ください。 今回は「Iterator」です。

# Summarise

本書のp2によると、 Iteratorとは

何かがたくさん集まっているときに、それを順番に指し示していき、全体をスキャンしていく処理を行うためのもの

とあります。要は繰り返し構文ですね。

pythonに限らず、(モダンな)ほどんどの言語は foryeildappendなどの構文がサポートしてあり、わざわざこのデザインパターンを使わなくても内部実装として用意してあります。ですが、内部実装を確認するためにもiteratorの実装を確かめてみましょう。

# Practice

## Specification

本棚を示すプログラムを作成します。

本棚は class BookShelf として表し、本は class Book として表現します。本棚に、 name Filed(本の名前)を設定したclass Book を追加していきます。

最後に本棚から本を取り出していって、 name Filed(本の名前)を標準出力します。絶対に forappend を使ってはいけません(自前で実装しましょう)

## 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 BookShelfdef 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 Aggregationclass 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

--

--