24 05 2020

迭代器模式

模式定义

迭代器模式(Iterator),又叫做游标(Cursor)模式。提供一种方法访问一个容器(Container)对象中各个元素,而又不需暴露该对象的内部细节。 当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。另外,当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。迭代器模式为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。


迭代器模式的优势

访问一个聚合对象的内容而无需暴露它的内部表示  

支持对聚合对象的多种遍历  

为遍历不同的聚合结构提供一个统一的接口  


代码示例

Iterator\Book.class.php
<?php
namespace Iterator;

class Book
{
    private $author;

    private $title;

    public function __construct($title, $author)
    {
        $this->title = $title;
        $this->author = $author;
    }

    public function getAuthor()
    {
        return $this->author;
    }

    public function getTitle()
    {
        return $this->title;
    }

    public function getAuthorAndTitle()
    {
        return $this->getTitle() . ' by ' . $this->getAuthor();
    }
}


Iterator\BookList.class.php
<?php
namespace Iterator;

class BookList implements \Countable
{
    private $books;

    public function getBook($bookNumberToGet)
    {
        if(isset($this->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) {
            if($book->getAuthorAndTitle() == $bookToRemove->getAuthorAndTitle()){
                unset($this->books[$key]);
            }
        }
    }

    /**
     * @inheritDoc
     */
    public function count()
    {
        return $this->count($this->books);
    }
}


Iterator\BookListIterator.class.php
<?php
namespace Iterator;

class BookListIterator implements \Iterator
{

    private $bookList;

    protected $currentBook = 0;

    public function __construct(BookList $bookList)
    {
        $this->bookList = $bookList;
    }

    /**
     * @inheritDoc
     */
    public function current()
    {
        return $this->bookList->getBook($this->currentBook);
    }

    /**
     * @inheritDoc
     */
    public function next()
    {
        $this->currentBook++;
    }

    /**
     * @inheritDoc
     */
    public function key()
    {
        return $this->currentBook;
    }

    /**
     * @inheritDoc
     */
    public function valid()
    {
        return null !== $this->bookList->getBook($this->currentBook);
    }

    /**
     * @inheritDoc
     */
    public function rewind()
    {
        $this->currentBook = 0;
    }
}


Iterator\IteratorTest.php
<?php
spl_autoload_register(function ($className){
    $className = str_replace('\\', '/', $className);
    include $className.".class.php";
});

use Iterator\Book;
use Iterator\BookList;
use Iterator\BookListIterator;

$bookList = new BookList();
$bookList->addBook(new Book('Learning PHP Design Patterns', 'William Sanders'));
$bookList->addBook(new Book('Professional Php Design Patterns', 'Aaron Saray'));
$bookList->addBook(new Book('Clean Code', 'Robert C. Martin'));

$iterator = new BookListIterator($bookList);

while ($iterator->valid()) {
    echo $iterator->current()->getAuthorAndTitle() . "\n";
    $iterator->next();
}


测试示例:

php Iterator/IteratorTest.php 

输出:
Learning PHP Design Patterns by William Sanders
Professional Php Design Patterns by Aaron Saray
Clean Code by Robert C. Martin


总结

通过引入迭代器可以将数据的遍历功能从聚合对象中分离出来,聚合对象只负责存储数据,而遍历数据由迭代器来完成。

PHP标准库(SPL)中提供了迭代器接口 Iterator,要实现迭代器模式,实现该接口即可。




代码地址:https://github.com/798256478/design-patterns/tree/master/Iterator