質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iteratorパターン

iteratorパターンとは、オブジェクト指向プログラミングのデザインパターンです。コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供することを目的とします。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

Q&A

解決済

1回答

5739閲覧

getIterator()とArrayIteratorの目的がわかりません

awa

総合スコア34

iteratorパターン

iteratorパターンとは、オブジェクト指向プログラミングのデザインパターンです。コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供することを目的とします。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

0グッド

2クリップ

投稿2018/07/04 15:12

デザインパターンというものを知り、中でもIteratorパターンを学習し始めました。
IteratorAggregateインターフェースを活用した下記のコード内で、
getIterator()を使って、わざわざ$this->membersをArrayIteratorでラップして返す目的がわかりません。
IteratorAggregateはインターフェースのため、getIterator()をオーバーライドしないといけないということはわかっているのですが、なぜわざわざそんなことをするのかがわかりません。
foreachも$iterator as $memberではなく$members as $memberで表示上は同じになりますし・・・。
Iteratorパターンの本質をわかっていないのでしょうか。

php

1<?php 2 3class Member{ 4 private $id; 5 private $lastname; 6 private $firstname; 7 private $email; 8 private $password; 9 10 public function __construct($id, $lastname, $firstname, $email, $password) 11 { 12 $this->setId($id); 13 $this->setLastname($lastname); 14 $this->setFirstname($firstname); 15 $this->setEmail($email); 16 $this->setPassword($password); 17 } 18 19 20 public function setId(int$id){ 21 $this->id = $id; 22 } 23 24 public function getId(){ 25 return $this->id; 26 } 27 28 public function setLastname($lastname){ 29 $this->lastname = $lastname; 30 } 31 32 public function getLastname(){ 33 return $this->lastname; 34 } 35 36 public function setFirstname($firstname){ 37 $this->firstname = $firstname; 38 } 39 40 public function getFirstname(){ 41 return $this->firstname; 42 } 43 44 public function setEmail($email){ 45 $this->email = $email; 46 } 47 48 public function getEmail(){ 49 return $this->email; 50 } 51 52 public function setPassword($password){ 53 $this->password = $password; 54 } 55 56 public function getPassword(){ 57 return $this->password; 58 }

php

1<?php 2 3class Members implements IteratorAggregate{ 4 private $members = []; 5 6 public function add(Member $member) 7 { 8 $this->members[] = $member; 9 } 10 11 public function getIterator() 12 { 13 return new ArrayIterator($this->members); 14 } 15}

php

1<?php 2 3require_once 'memberclass.php'; 4require_once 'membersclass.php'; 5 6//ダミーの会員データを作成 7$member1 = new Member(1, "姓1", "名1", "名1", "email1@example.com", "password1"); 8$member2 = new Member(2, "姓2", "名2", "名2", "email2@example.com", "password2"); 9$member3 = new Member(3, "姓3", "名3", "名3", "email3@example.com", "password3"); 10$member4 = new Member(4, "姓4", "名4", "名4", "email4@example.com", "password4"); 11$member5 = new Member(5, "姓5", "名5", "名5", "email5@example.com", "password5"); 12 13//Membersクラスに会員データを追加 14$members = new Members(); 15$members->add($member1); 16$members->add($member2); 17$members->add($member3); 18$members->add($member4); 19$members->add($member5); 20 21//getIteratorによりイテレーターを取得 22$iterator = $members->getIterator(); 23 24//ループ処理 25foreach ($iterator as $member){ 26 print $member->getId()." "; 27 print $member->getLastname()." "; 28 print $member->getFirstname()." "; 29 print $member->getEmail()." "; 30 print $member->getPassword()." "; 31}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papinianus

2018/07/05 02:09

「foreachも$iterator as $memberではなく$members as $memberで表示上は同じになりますし」のところは、どういう実装にするつもりなのでしょうか。membersクラスを作らないで単にmembersを配列に入れるってことですか?
awa

2018/07/06 06:59

そうです、わかりにくくてすみません。
guest

回答1

0

ベストアンサー

デザインパターンをやるくらいなので、オブジェクト指向に取り組もうとしているという前提で。(頭のすみに置いておいて欲しいのですが、OOPとかデザパタは教科書・研修レベルでやるとまわりくどいだけにしか思えません)

Iteratorパターンは、forでループできないものをforeachできるようにするためのものです。
PHPでは説明しにくいのですが、順序のない集合(SetとかHashSetとか)や、辞書(PHPだと連想配列)、サイズが変動する配列(ListとかArrayListとか)などを反復による繰り返しでループできるようにするためのものです。
PHPはSetはないですし、(他の言語でも最近は組み込みで)連想配列やList(配列が可変なので)がforeachできるので「何で必要なの」という感覚はやむを得ないと思います。

さて、そんな現状であらためて、Iteratorパターンで何が嬉しいかの話なんですが、まずは設計の観点として、実装を隠蔽すべきです。具体的なインスタンスを配列につっこむといった「何でも組み込みのデータ型だけでやろうとする」のはオブジェクト指向がやろうとしていることと思想レベルで対立しています。データのリストそのものをpublicに公開すべきではないし(アクセサやgetIteratorでアクセスさせるべき)、そもそも配列を外で組み立てて、配列でループするなんてことは、プログラム規模が大きくなってきたら破綻します。
設計ではない、実用上の意味として、列挙にロジックがあることがあるのではないでしょうか?今回は全てのメンバーを全部ただただ回していますが、例えばMemberに仮登録(メール認証待ち)とかのステータスがあるとしたら、getIteratorしたときに、あるときは仮登録の人は除外して欲しいし、あるときは除外しないで欲しい、みたいな判断がくることがあっていいと思います。このとき、isActive()という関数はどこに実装するのが適切でしょうか。もし$membersの配列を使うとしたら、配列に入れるときに、判断するのでしょうか。あるいは、array_filterを書くのでしょうか。Memberクラスに関するフィルタリングをクラス外で実装しはじめると保守の点でつらいです(年齢で絞ったりなど要件が拡張するパターンも考えてみてください)。getIterator()にオプションをつけるなどして、Iterator側でやったほうがいいのではないでしょうか。

まとまりがない気もしますが、まとめますと、配列っぽいデータをそのまま返しているから配列でいいように思えるが、それはそういうサンプルを書いているからです。まわりくどいことが生きる局面はあるはずですが、それはそれなりに作っていかないと実感としては分かりません。無理矢理局面を考えると↑のようなことが考えられます。

投稿2018/07/06 07:46

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

awa

2018/07/06 16:46

ご回答ありがとうございます。下記のように理解しました。  ・Iteratorパターンはオブジェクト指向の設計パターンでありカプセル化できるメリットがある。ここでいうカプセル化とは配列要素をとりだしていくためのインターフェイスをIteratorとして設けることであり、これがあることで条件を満たす要素を取り出す等の場合には、呼び出し元であるクラス外ではなくIterator側に処理を記述することができる。大規模なプログラムであるほど機能変更の際にどれだけ保守性が高いかが効いてくる。 もし誤解あればご指導ください。 大規模なプログラムを書いたことがないので正直まだオブジェクト指向のメリットを実感できてはいませんが、理解できるようにまずは頑張ってみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問