Pythonでデザインパターン 壱ノ型「Iterator」
今回はPythonの勉強目的でデザインパターンのIteratorをやってみました。
他のパターンにつきましては、以下の目次記事をご参照ください。
Iteratorとは
直訳だと「繰り返す」や「反復」という意味になります。
wikiには「コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供する」とあります。
Iteratorについて考えてみる
プログラミング言語には配列、リスト、ハッシュテーブルなどのデータを1つのオブジェクト(集合体)にまとめる仕組みがあります。
しかし、データへアクセスする方法はオブジェクト毎に異なるので、オブジェクトを利用するユーザは「オブジェクト毎にデータにアクセスする処理」を書かなければいけなくなります。
例えば、以下のような感じです。
添え字を数値としてアクセスする一般的な配列 = arry[N] 添え字をキーワードとしてアクセスする連想配列 = arry["keyword"] アクセッサーをもつオブジェクト = arry.get(N) などなど
そこで「共通の方法でオブジェクト(集合体)にアクセスしてデータを取り出す仕組みを提供するよ!」といっているのがIteratorパターンかなと思っています。
イメージとしては以下のような感じです。
if __name__ == '__main__': dataA = list(range(5)) # 0, 1, 2, 3, 4 dataB = {"AAA" : 1, "BBB" : 2, "CCC" : 3, "DDD" : 4} # dataAに対するIteratorを作成 itr = Iterator(dataA) while itr.hasNext() : # 次のデータがなくなるまで繰り返し print(itr.next()) # データを取り出して次へ # dataBに対するIteratorを作成 itr = Iterator(dataB) while itr.hasNext() : # 次のデータがなくなるまで繰り返し print(itr.next()) # データを取り出して次へ
整数型の配列dataAと文字列型をキーとする連想配列集dataBがあったとします。
このイメージだと、まずdataAに対するIteratorというオブジェクトを作成しています。
dataAへのアクセスはIteratorオブジェクトが持つhasNext()とnext()というメソッドを使用して行います。
この例では、hasNext()は集合体から読み出せるデータがあるかどうかを判定する機能、
next()は集合体から次のデータを取り出す機能を提供しています。
hasNext()を使ってデータが無くなるまで繰り返しnext()を呼び出しています。
その後、集合体dataBに対するIteratorオブジェクトを作成して同様のことを行います。
これによりユーザは、dataAでもdataBでも共通の方法で集合体にアクセスできるようになります。
サンプルプログラム
以下、サンプルプログラムです。
StudentListが集合体クラスで、Studentが集合体で管理するデータクラスです。
MyStudentListはStudentListを継承しているため集合体としても機能するようにもなっており、
iterator()メソッドで自分自身を渡してMyStudentListIteratorを生成するようになっています。
MyStudentListIteratorは生成されたタイミングでMyStudentListのインスタンスを保持します。
このインスタンスを使って、next()やhasNext()で集合体を操作する機能を実現しています。
# coding: utf-8 from abc import ABC, ABCMeta, abstractmethod # Iteratorインタフェース class Iterator(metaclass=ABCMeta) : @abstractmethod def hasNext() : pass @abstractmethod def next() : pass # Aggregateインタフェース class Aggregate(metaclass=ABCMeta) : @abstractmethod def iterator() : pass # データクラス class Student(object) : def __init__(self, name, sex) : self.__name = name self.__sex = sex def getName(self) : return self.__name def getSex(self) : return self.__sex # データリストクラス(集合体) class StudentList(object) : def __init__(self) : self.__students = [] def add(self, student) : self.__students.append(student) def getStudentAt(self, index) : return self.__students[index] def getLastNum(self) : return len(self.__students) # Aggregateインタフェースを実装したクラス class MyStudentList(StudentList, Aggregate) : def __init__(self) : StudentList.__init__(self) def iterator(self) : return MyStudentListIterator(self) # Iteratorインタフェースを実装したクラス class MyStudentListIterator(Iterator) : def __init__(self, list) : self.__myStudentList = list self.__index = 0 def hasNext(self) : if self.__myStudentList.getLastNum() > self.__index : return True else : return False def next(self) : student = self.__myStudentList.getStudentAt(self.__index) self.__index += 1 return student # ユースケース if __name__ == '__main__': list = MyStudentList() list.add(Student("AAA", 1)) list.add(Student("BBB", 0)) list.add(Student("CCC", 1)) itr = list.iterator() while itr.hasNext() : print(itr.next().getName())
実行結果は以下のとおりです。
$ python Iterator.py AAA BBB CCC