1、模式定義
迭代器模式 (Iterator),又叫做遊標(Cursor)模式。提供一種方法訪問一個容器(Container)對象中各個元素,而又不需暴露該對象的內部細節。
當你需要訪問一個彙總對象,而且不管這些對象是什麼都需要遍曆的時候,就應該考慮使用迭代器模式。另外,當需要對聚集有多種方式遍曆時,可以考慮去使用迭代器模式。迭代器模式為遍曆不同的聚集結構提供如開始、下一個、是否結束、當前哪一項等統一的介面。
PHP標準庫(SPL)中提供了迭代器介面 Iterator,要實現迭代器模式,實現該介面即可。
2、UML類圖
3、範例程式碼
Book.php
author = $author; $this->title = $title; } public function getAuthor() { return $this->author; } public function getTitle() { return $this->title; } public function getAuthorAndTitle() { return $this->getTitle() . ' by ' . $this->getAuthor(); }}
BookList.php
books[$bookNumberToGet])) { return $this->books[$bookNumberToGet]; } return null; } public function addBook(Book $book) { $this->books[] = $book; } public function removeBook(Book $bookToRemove) { foreach ($this->books as $key => $book) { /** @var Book $book */ if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) { unset($this->books[$key]); } } } public function count() { return count($this->books); }}
BookListIterator.php
bookList = $bookList; } /** * Return the current book * @link http://php.net/manual/en/iterator.current.php * @return Book Can return any type. */ public function current() { return $this->bookList->getBook($this->currentBook); } /** * (PHP 5 >= 5.0.0)
* Move forward to next element * @link http://php.net/manual/en/iterator.next.php * @return void Any returned value is ignored. */ public function next() { $this->currentBook++; } /** * (PHP 5 >= 5.0.0)
* Return the key of the current element * @link http://php.net/manual/en/iterator.key.php * @return mixed scalar on success, or null on failure. */ public function key() { return $this->currentBook; } /** * (PHP 5 >= 5.0.0)
* Checks if current position is valid * @link http://php.net/manual/en/iterator.valid.php * @return boolean The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. */ public function valid() { return null !== $this->bookList->getBook($this->currentBook); } /** * (PHP 5 >= 5.0.0)
* Rewind the Iterator to the first element * @link http://php.net/manual/en/iterator.rewind.php * @return void Any returned value is ignored. */ public function rewind() { $this->currentBook = 0; }}
BookListReverseIterator.php
bookList = $bookList; $this->currentBook = $this->bookList->count() - 1; } /** * Return the current book * @link http://php.net/manual/en/iterator.current.php * @return Book Can return any type. */ public function current() { return $this->bookList->getBook($this->currentBook); } /** * (PHP 5 >= 5.0.0)
* Move forward to next element * @link http://php.net/manual/en/iterator.next.php * @return void Any returned value is ignored. */ public function next() { $this->currentBook--; } /** * (PHP 5 >= 5.0.0)
* Return the key of the current element * @link http://php.net/manual/en/iterator.key.php * @return mixed scalar on success, or null on failure. */ public function key() { return $this->currentBook; } /** * (PHP 5 >= 5.0.0)
* Checks if current position is valid * @link http://php.net/manual/en/iterator.valid.php * @return boolean The return value will be casted to boolean and then evaluated. * Returns true on success or false on failure. */ public function valid() { return null !== $this->bookList->getBook($this->currentBook); } /** * (PHP 5 >= 5.0.0)
* Rewind the Iterator to the first element * @link http://php.net/manual/en/iterator.rewind.php * @return void Any returned value is ignored. */ public function rewind() { $this->currentBook = $this->bookList->count() - 1; }}
4、測試代碼
Tests/IteratorTest.php
bookList = new BookList(); $this->bookList->addBook(new Book('Learning PHP Design Patterns', 'William Sanders')); $this->bookList->addBook(new Book('Professional Php Design Patterns', 'Aaron Saray')); $this->bookList->addBook(new Book('Clean Code', 'Robert C. Martin')); } public function expectedAuthors() { return array( array( array( 'Learning PHP Design Patterns by William Sanders', 'Professional Php Design Patterns by Aaron Saray', 'Clean Code by Robert C. Martin' ) ), ); } /** * @dataProvider expectedAuthors */ public function testUseAIteratorAndValidateAuthors($expected) { $iterator = new BookListIterator($this->bookList); while ($iterator->valid()) { $expectedBook = array_shift($expected); $this->assertEquals($expectedBook, $iterator->current()->getAuthorAndTitle()); $iterator->next(); } } /** * @dataProvider expectedAuthors */ public function testUseAReverseIteratorAndValidateAuthors($expected) { $iterator = new BookListReverseIterator($this->bookList); while ($iterator->valid()) { $expectedBook = array_pop($expected); $this->assertEquals($expectedBook, $iterator->current()->getAuthorAndTitle()); $iterator->next(); } } /** * Test BookList Remove */ public function testBookRemove() { $this->bookList->removeBook($this->bookList->getBook(0)); $this->assertEquals($this->bookList->count(), 2); }}