iteraterを用いた抽象度の比較
iteratorとは
iteratorパターンは、オブジェクトの集合を「要素から列挙する概念」だけを抜き出したパターンである。
インタフェースIterator<E>
イテレータを使用すると、明確なセマンティックスに基づく反復処理の間に、呼出し側は基本となるコレクションから要素を削除できる。
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Iterator.html
からの引用であるが、簡単に言うと、呼び出し側は、具象を認知することなく反復処理を行うことができる。これは、オブジェクト指向における「tell, dont ask」にも通ずる概念である。
foreachで直接回す事との違いは?
ここで問題になってくるのは、phpは、arrayをforeachで直接回せるという事実である。配列ループ処理を行えるお手頃な機能があるなら、 わざわざiteratorを使用する意味ないんじゃ? みたいな疑問も出てくるだろう。
実際のコード
arrayをそのままforeachで回す関数
function showAll(array $array)
{
foreach ($array as $n) {
echo $n . "\n";
}
}
showAll([1,2,3]);
function showAll(Iterator $iterator)
{
foreach ($iterator as $element) {
echo $element . "\n";
}
}
showAll(new ArrayIterator([1,2,3]));
正直、iteratorを使う必要ないと思うだろう。
先に行ってしまうが、foreachだと、最初にすべての要素を読み込まなくてはいけないのである。
しかし、iteratorは順番に1つずつデータを取り出して処理している。
ここに面白さがある。
iteratorを使用するメリットとは
arrayを使わず、一度iteratorを仲介するやり方は回りくどいだけだと感じるだろう。
では、iterator版のコードに、フォルダ内のファイルを列挙するfilesystemIteratorと組み合わせたとき、どうなるだろう。
ファイルシステムへのアクセスは、整数の並びなどよりはるかにかなりの時間を必要とする処理であり、となると、ファイルストリームや何百件のデータベースレコードをオンメモリの配列に格納するのかという話になってくる。ストーリーミング処理(ベルトコンベアー式)が適しているのは言うまでもない。
配列要素の繰り返しも、重い処理も同じ操作に一般化できる抽象概念がイテレータの意味である。
Discussion