Itaratorパターンとは

# Iteratorパターン とは ??
「**Iterate**」は「◯◯を繰り返す」という意味で、
プログラミングにおいては「for」や「while」などを用いた「**反復処理をする**」という意味で使われる。

「**Iterator パターン**」は、集約オブジェクト（コレクションオブジェクト）の中の要素を列挙する手段を提供して、具体的な列挙方法を集約オブジェクトから隠蔽することで、列挙方法を抽象化します。

とのこと:thinking:

# 集約オブジェクトとは ??
何らかの「情報の集まり」を格納したオブジェクトのこと。

```php
// 「書籍」集約オブジェクト
$book_list = [
    '星の王子さま',
    '銀河鉄道の夜',
    '吾輩は猫である',
    '西の魔女が死んだ',
    'コーヒーが冷めないうちに'
];
```

# 集約オブジェクトをIterateする !!
foreachで回すだけ。

```php
foreach ($book_list as $book) {
	echo $book;
}
```

　
後日集約オブジェクトの$book_listの中身が変わって、下記になったとすると...

```php
$book_list = [
    [
        'title' => '星の王子さま',
        'author' => 'サン＝テグジュペリ'
    ],
    [
        'title' => '銀河鉄道の夜',
        'author' => '宮沢賢治'
    ],
    [
        'title' => '吾輩は猫である',
        'author' => '夏目漱石'
    ],
    [
        'title' => '西の魔女が死んだ',
        'author' => '梨木香歩'
    ],
    [
        'title' => 'コーヒーが冷めないうちに',
        'author' => '川口俊和'
    ]
];
```

　
データの構造が変わったので、同じ出力をするためには以前に書いたコードを書き直さなければならない。

```php
foreach ($book_list as $book_obj) {
	foreach ($book_obj as $title => $author) {
		echo $title . ' - ' . $author;
	}
}
```

　
更にIDが追加されて、IDの昇順に並び替えたい ! となると...

```php
$book_list = [
    [
        'title' => '星の王子さま',
        'author' => 'サン＝テグジュペリ',
        'ID' => 3
    ],
    [
        'title' => '銀河鉄道の夜',
        'author' => '宮沢賢治',
        'ID' => 5
    ],
    [
        'title' => '吾輩は猫である',
        'author' => '夏目漱石',
        'ID' => 1
    ],
    [
        'title' => '西の魔女が死んだ',
        'author' => '梨木香歩',
        'ID' => 4
    ],
    [
        'title' => 'コーヒーが冷めないうちに',
        'author' => '川口俊和',
        'ID' => 2
    ]
```

　
また以前のコードの改修作業が必要になる。
これが、10箇所、20箇所で使っていたら全て置き換えるのは大変なので、
こういうときに「Iteratorパターン」を使用する！

# どのように実装する ??

集約オブジェクトに「Iteratorオブジェクト」を提供させることで解決！
「Iteratorオブジェクト」は集約オブジェクトを列挙する方法を知っているので、
クライアント（Iteratorを使うオブジェクト）は実装の詳細を知る必要はなく、
「Iteratorオブジェクト」の使い方さえ知っていればよい 🙆⭕️

後からいくら集約オブジェクトのタイプが増えても、クライアント側の記述そのままでよくなるため、プログラムの柔軟性がぐっと上がる :raised_hands:

```php
<?php

/* -----------------------
 * インターフェイス
 * -----------------------*/

// Aggregate Interface
interface BookList {
	/**
	 * Iteratorを返すメソッド
	 * @return BookIterator
	 */
	public function createIterator();
}

// Iterator Interface
interface BookIterator {
	/**
	 * 次の要素があるかどうかを判定する
	 * @return bool
	 */
	public function hasNext();

	/**
	 * 次の要素を返し、ポインターを進める
	 * @return mixed
	 */
	public function next();
}

/* -----------------------
 * Iteratorの実装
 * -----------------------*/

// Iteratorクラス、このクラス内で列挙の手順を記述する。
// BookIteratorインターフェイスを実装するようにする。
class BookList_Simple_Iterator implements BookIterator {
	private $books;
	private $position = 0;

	function __construct($books) {
		$this->books = $books;
	}

	public function hasNext() {
		return isset($this->books[$this->position]);
	}

	public function next() {
		return $this->books[$this->position++];
	}

}

// 別のIteratorクラス、列挙の手順が一個前と違うけど、
// 同じBookIteratorインターフェイスを持っているので、使う側からしたら差異はない
class BookList_Detailed_Iterator implements BookIterator {
	protected $books;
	private $position = 0;

	function __construct($books) {
		$this->books = $books;
	}

	public function hasNext() {
		return isset($this->books[$this->position]);
	}

	public function next() {
		$book = $this->books[$this->position++];
		$title = $book['title'];
		$author = $book['author'];

		return $title . ' - ' . $author;
	}
}

// 更に別のIteratorクラス、「BookList_Detailed_Iterator」と似ているので、継承する
class BookList_Detailed_OrderByID_Iterator extends BookList_Detailed_Iterator implements BookIterator {
	function __construct($books) {
		usort($books, function($a, $b) {
			return (int)$a['id'] > (int)$b['id'];
		});
		$this->books = $books;
	}
}

/* -----------------------------
 * Aggregate(集約オブジェクト)の実装
 * -----------------------------*/

// クラス間で共有しているメソッドたちを分離しておく。
trait BookList_Methods {
	private $book_list;

	function __construct($books) {
		$this->book_list = $books;
	}

	public function add_to_list($book) {
		$this->book_list[] = $book;
	}

	public function get_book_list() {
		return $this->book_list;
	}
}

// 集約オブジェクト　書籍一覧[簡易版]
class Books_Simple implements BookList {
	use BookList_Methods;

	public function createIterator() {
		return new BookList_Simple_Iterator($this->book_list);
	}
}

// 集約オブジェクト　書籍一覧[詳細版]
class Books_Detailed implements BookList {
	use BookList_Methods;

	public function createIterator() {
		return new BookList_Detailed_Iterator($this->book_list);
	}
}

// 集約オブジェクト　書籍一覧[詳細+並び替え版]
class Books_Detailed_OrderByID implements BookList {
	use BookList_Methods;

	public function createIterator() {
		return new BookList_Detailed_OrderByID_Iterator($this->book_list);
	}
}

/* --------------------------
 * クライアントである「書籍クラス」
 * --------------------------*/

class Book {
	/** @type  BookIterator $book_iterator */
	private $book_iterator;

	function __construct(BookList $book_list) {
		// Iteratorオブジェクトを持たせる
		$this->book_iterator = $book_list->createIterator();
	}

	function print_books() {
		// Iteratorオブジェクトを使う
		while ($this->book_iterator->hasNext()) {
			$book = $this->book_iterator->next();
			echo $book . '<br>';
		}
	}
}

/* -----------------------
 * メイン処理
 * -----------------------*/
 
// 書籍一覧のデータ[詳細]
$books_detailed_array = [
    [
        'title' => '星の王子さま',
        'author' => 'サン＝テグジュペリ',
        'ID' => 3
    ],
    [
        'title' => '銀河鉄道の夜',
        'author' => '宮沢賢治',
        'ID' => 5
    ],
    [
        'title' => '吾輩は猫である',
        'author' => '夏目漱石',
        'ID' => 1
    ],
    [
        'title' => '西の魔女が死んだ',
        'author' => '梨木香歩',
        'ID' => 4
    ],
    [
        'title' => 'コーヒーが冷めないうちに',
        'author' => '川口俊和',
        'ID' => 2
    ]

// 書籍一覧のデータ[簡易]
$books_simple_array = [
    '星の王子さま',
    '銀河鉄道の夜',
    '吾輩は猫である',
    '西の魔女が死んだ',
    'コーヒーが冷めないうちに'
];

// それぞれ違う集約オブジェクトで書籍クラスをインスタンス化
$book_a = new Book(new Books_Detailed($books_detailed_array));
$book_b = new Book(new Books_Simple($books_simple_array));
$book_c = new Book(new Books_Detailed_OrderByID($books_detailed_array));

?>

<section>
	<h1>book_a</h1>
	<?php $book_a->print_books(); ?>
</section>

<section>
	<h1>book_b</h1>
	<?php $book_b->print_books(); ?>
</section>

<section>
	<h1>book_c</h1>
	<?php $book_c->print_books(); ?>
</section>
```

```html
<!-- 出力 -->

book_a
星の王子さま - サン＝テグジュペリ
銀河鉄道の夜 - 宮沢賢治
吾輩は猫である - 夏目漱石
西の魔女が死んだ - 梨木香歩
コーヒーが冷めないうちに - 川口俊和

book_b
星の王子さま
銀河鉄道の夜
吾輩は猫である
西の魔女が死んだ
コーヒーが冷めないうちに

book_c
吾輩は猫である - 夏目漱石
コーヒーが冷めないうちに - 川口俊和
星の王子さま - サン＝テグジュペリ
西の魔女が死んだ - 梨木香歩
銀河鉄道の夜 - 宮沢賢治
```
# メリット
- 集約オブジェクト内部のデータ構造を隠蔽することができるため、コードの柔軟性が向上する。

- Iteratorオブジェクトを使用することで、コレクション内部の要素に簡単にアクセスすることができる。

- Iteratorオブジェクトは、コレクション内の要素を順番に処理するため、効率的な処理が可能になる。

# デメリット
- 実装が複雑になる。Iteratorパターンを実装するには、Iteratorインターフェースを定義して、各コレクションの具象Iteratorクラスを実装する必要がある。また、コレクションやデータ構造を更新した際には、Iteratorも同時に更新する必要がある。

- パフォーマンスの低下。Iteratorパターンを利用することで、要素にアクセスするためにインスタンスを生成する必要がある。Iteratorオブジェクトは集約オブジェクトと1対1の関係になるため、多数のIteratorオブジェクトを作成するとこれにより、パフォーマンスが低下する可能性がある。

# MEMO
interface
メソッドの実装を定義せずに、 クラスが実装する必要があるメソッドを指定するコードを作成する。
[https://www.php.net/manual/ja/language.oop5.interfaces.php](https://www.php.net/manual/ja/language.oop5.interfaces.php)

implements
interfaceを使用するときに使う演算子
[https://www.php.net/manual/ja/language.oop5.interfaces.php](https://www.php.net/manual/ja/language.oop5.interfaces.php)

trait
いくつかの機能をまとめてコードを再利用するためのもの。
トレイトのメリットは、継承しなくても機能を共有できるところ。
[https://www.php.net/manual/ja/language.oop5.traits.php](https://www.php.net/manual/ja/language.oop5.traits.php)