LoginSignup
0
0

Itaratorパターンとは

Last updated at Posted at 2023-08-15

Iteratorパターン とは ??

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

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

とのこと:thinking:

集約オブジェクトとは ??

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

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

集約オブジェクトをIterateする !!

foreachで回すだけ。

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

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

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

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

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

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

$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

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

// 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>
<!-- 出力 -->

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

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

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0