mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-06-06 05:55:09 +02:00
Behavioral\Iterator restructured
This commit is contained in:
parent
3e515daa0f
commit
d225a43de7
32
Behavioral/Iterator/Book.php
Normal file
32
Behavioral/Iterator/Book.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DesignPatterns\Behavioral\Iterator;
|
||||||
|
|
||||||
|
class Book
|
||||||
|
{
|
||||||
|
|
||||||
|
private $author;
|
||||||
|
|
||||||
|
private $title;
|
||||||
|
|
||||||
|
public function __construct($title, $author)
|
||||||
|
{
|
||||||
|
$this->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();
|
||||||
|
}
|
||||||
|
}
|
42
Behavioral/Iterator/BookList.php
Normal file
42
Behavioral/Iterator/BookList.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DesignPatterns\Behavioral\Iterator;
|
||||||
|
|
||||||
|
class BookList implements \Countable
|
||||||
|
{
|
||||||
|
|
||||||
|
private $books;
|
||||||
|
|
||||||
|
public function getBook($bookNumberToGet)
|
||||||
|
{
|
||||||
|
if ((int)$bookNumberToGet <= $this->count()) {
|
||||||
|
return $this->books[$bookNumberToGet];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addBook(Book $book)
|
||||||
|
{
|
||||||
|
$this->books[] = $book;
|
||||||
|
|
||||||
|
return $this->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeBook(Book $bookToRemove)
|
||||||
|
{
|
||||||
|
foreach ($this as $key => $book) {
|
||||||
|
/** @var Book $book */
|
||||||
|
if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) {
|
||||||
|
unset($this->books[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return count($this->books);
|
||||||
|
}
|
||||||
|
}
|
77
Behavioral/Iterator/BookListIterator.php
Normal file
77
Behavioral/Iterator/BookListIterator.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DesignPatterns\Behavioral\Iterator;
|
||||||
|
|
||||||
|
class BookListIterator implements \Iterator
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BookList
|
||||||
|
*/
|
||||||
|
protected $bookList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $currentBook = 0;
|
||||||
|
|
||||||
|
public function __construct(BookList $bookList)
|
||||||
|
{
|
||||||
|
$this->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)<br/>
|
||||||
|
* 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)<br/>
|
||||||
|
* 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)<br/>
|
||||||
|
* 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 $this->currentBook < $this->bookList->count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (PHP 5 >= 5.0.0)<br/>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
23
Behavioral/Iterator/BookListReverseIterator.php
Normal file
23
Behavioral/Iterator/BookListReverseIterator.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DesignPatterns\Behavioral\Iterator;
|
||||||
|
|
||||||
|
class BookListReverseIterator extends BookListIterator
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct(BookList $bookList)
|
||||||
|
{
|
||||||
|
$this->bookList = $bookList;
|
||||||
|
$this->currentBook = $this->bookList->count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->currentBook--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return 0 <= $this->currentBook;
|
||||||
|
}
|
||||||
|
}
|
@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DesignPatterns\Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* class File
|
|
||||||
*
|
|
||||||
* THIS EXAMPLE ALSO APPLIES THE COMPOSITE PATTERN
|
|
||||||
*/
|
|
||||||
class File
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var RowSet
|
|
||||||
*/
|
|
||||||
protected $rowSet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $pathName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $pathName
|
|
||||||
*/
|
|
||||||
public function __construct($pathName)
|
|
||||||
{
|
|
||||||
$this->rowSet = new Rowset($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* processes the rowSet
|
|
||||||
*/
|
|
||||||
public function process()
|
|
||||||
{
|
|
||||||
// this is the place to show how using an iterator, with foreach
|
|
||||||
// See the CardGame.php file
|
|
||||||
$this->rowSet->process();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DesignPatterns\Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class Row
|
|
||||||
*/
|
|
||||||
class Row
|
|
||||||
{
|
|
||||||
protected $data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function __construct($data)
|
|
||||||
{
|
|
||||||
$this->data = $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function process()
|
|
||||||
{
|
|
||||||
// do some fancy things here ...
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DesignPatterns\Iterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class RowSet
|
|
||||||
*/
|
|
||||||
class RowSet implements \Iterator
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var
|
|
||||||
*/
|
|
||||||
protected $currentRow;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $lineNumber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $file
|
|
||||||
*/
|
|
||||||
public function __construct($file)
|
|
||||||
{
|
|
||||||
$this->file = $file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* composite pattern: run through all rows and process them
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function process()
|
|
||||||
{
|
|
||||||
// this actually calls rewind(), { next(), valid(), key() and current() :}
|
|
||||||
/**
|
|
||||||
* THE key feature of the Iterator Pattern is to provide a *public contract*
|
|
||||||
* to iterate on a collection without knowing how items are handled inside
|
|
||||||
* the collection. It is not just an easy way to use "foreach"
|
|
||||||
*
|
|
||||||
* One cannot see the point of iterator pattern if you iterate on $this.
|
|
||||||
* This example is unclear and mixed with some Composite pattern ideas.
|
|
||||||
*/
|
|
||||||
foreach ($this as $line => $row) {
|
|
||||||
$row->process();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function rewind()
|
|
||||||
{
|
|
||||||
// seek to first line from $this->file
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function next()
|
|
||||||
{
|
|
||||||
// read the next line from $this->file
|
|
||||||
if (!$eof) {
|
|
||||||
$data = ''; // get the line
|
|
||||||
$this->currentRow = new Row($data);
|
|
||||||
} else {
|
|
||||||
$this->currentRow = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function current()
|
|
||||||
{
|
|
||||||
return $this->currentRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function valid()
|
|
||||||
{
|
|
||||||
return null !== $this->currentRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function key()
|
|
||||||
{
|
|
||||||
// you would want to increment this in next() or whatsoever
|
|
||||||
return $this->lineNumber;
|
|
||||||
}
|
|
||||||
}
|
|
66
Behavioral/Iterator/Tests/IteratorTest.php
Normal file
66
Behavioral/Iterator/Tests/IteratorTest.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace DesignPatterns\Behavioral\Iterator\Tests;
|
||||||
|
|
||||||
|
use DesignPatterns\Behavioral\Iterator\Book;
|
||||||
|
use DesignPatterns\Behavioral\Iterator\BookList;
|
||||||
|
use DesignPatterns\Behavioral\Iterator\BookListIterator;
|
||||||
|
use DesignPatterns\Behavioral\Iterator\BookListReverseIterator;
|
||||||
|
|
||||||
|
class IteratorTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var BookList
|
||||||
|
*/
|
||||||
|
protected $bookList;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user