Help us understand the problem. What is going on with this article?

デザインパターン - Iterator

More than 3 years have passed since last update.

はじめに

増補改訂版Java言語で学ぶデザインパターン入門実践 Python 3に関する備忘録

Iteratorパターンとは

増補改訂版Java言語で学ぶデザインパターン入門

1つ1つ数え上げる

集合体の要素を、統一した方法で1つ1つ数え上げていく

実践 Python3

ふるまいに関するデザインパターン

コレクション型データやオブジェクト集合に対して、その実装の内部を公開せずに、その要素に順番にアクセスする方法を提供する。

Iteratorパターンの構成要素

役名 概要
Iterator 要素を順番にスキャン、要素の取り出しを行うインターフェース
ConcreteIterator Iteratorインタフェースを実際に実装するクラス
ここでは集合の内部構造に依存する走査処理が実装される
Aggregate 集合を管理し、Iteratorオブジェクトを生成するためのインタフェース
ConcreteAggregate Aggregateインタフェースを実装するクラス
ConcreteIteratorオブジェクトを生成する

Iteratorパターンのクラス図

Iteratorパターンのクラス図

PHPの場合

  • foreachがIteratorをサポート
  • 独自イテレータを作成する場合も、ジェネレータを利用すると便利(PHP5.5以上)

ジェネレータについて

コードをまとめる技術としてのイテレータとジェネレータ - Qiita
この記事に詳しく書かれています。
ジェネレータに関するサンプルコードをお借りして、ちょっと見ていこうと思います。

<?php

function filterOdd($ite) {
    $i = 0;
    foreach ($ite as $v) { ←③
        if ($i++ % 2) yield $v; ←①,
    }
}

// 0~100のうちの奇数のみを足した数を出力する。
$sum = 0;
foreach (filterOdd(range(0,100)) as $i) { ←②
    $sum += $i;
}
echo $sum, PHP_EOL;


//data.txtの奇数行だけを出力する。
foreach (filterOdd(new SplFileObject('data.txt')) as $line) {
    echo $line;
}

① returnではなく、yieldで値を返すことで、ジェネレータを生成する関数ができる。
② filterOddを実行することでジェネレータが生成。これを実行するために、foreachでイテレートを行う。
③ イテレートの度に、このforeach文が実行される。
④ yeildが実行された後は、処理は一度②の部分に移るが、再度イテレートされると前回実行されたyeildの箇所の処理に戻る。このとき、ジェネレータ内部構造は保持されたままなので、変数値も前回yeildが実行された状態で保たれている。
⑤ 次のyieldが見つからなくなった時点で、処理が終了。

ジェネレータはざっとこんな感じです。
パフォーマンスがよいので、メモリ節約を意識しなければいけない場合に有用です。

以下の記事でも、その点がわかりやすく述べられていますので参照ください。
PHP5.5の新機能を色々試してみた。 | アライドアーキテクツ エンジニアブログ

Pythonの場合

iteratorを返すiterableなオブジェクトであるためには、以下の3つの実装方法があります。

  1. シーケンス型プロトコルを満たす__getitem__()メソッドを使用
  2. 組み込み関数iter()を使用
  3. イテレータプロトコルを使用

最も簡単な方法が3つ目の「イテレータプロトコルを使用」することです。
またPHPと同じように

  • forループ / inステートメントがイテレータプロトコルをサポート
  • イテレータプロトコルを満たすための__iter__()メソッドの実装は、ジェネレータを利用すると便利

Pythonのジェネレータに関しては、Pythonのイテレータとジェネレータ - Qiitaがとても参考になりました。

Pythonのイテレータとジェネレータのまとめを引用しておきます。

  • イテレータ: 要素を反復して取り出すことのできるインタフェース
  • ジェネレータ: イテレータの一種であり、1要素を取り出そうとする度に処理を行い、要素をジェネレートするタイプのもの。Pythonではyield文を使った実装を指すことが多いと思われる

まとめ

  • Aggregateオブジェクトから「走査」のための責務を抜き出し、それをIteratorオブジェクトに割り当てる。
  • この「走査」と「操作」を切り分けたことおかげで、以下のことが実現可能に。
    1.Aggregateオブジェクトの内部構造を意識しなくとも、要素にアクセス
    2.複数の「走査」をAggregateオブジェクトに適用可能
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away