PHP设计模式-迭代器模式
引言:在理解迭代器模式之前,先了解一下迭代器的概念。迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器(container,例如链表或阵列)上遍访的接口,设计人员无需关心容器的内容。
迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。
概念:迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
迭代器模式的关键思想是:将对列表的访问和遍历从列表对象中分离出来并放入一个迭代器(Iterator)中。
我们可能没有注意到,我们每天都在使用迭代器模式。在PHP开发中,它潜藏在PHP数组类型和各种数组操作类型中。比如在PHP中的本地数组迭代:
<?php $arr = array('one','two','three'); $output = ''; reset($arr); do{ $output .= current($arr)."<br/>"; } while(next($arr)); echo $output;
reset()函数将迭代重新转到数组的开始,current()返回当前元素的值,next()则前进至数组中的下一个元素并返回新的current()值,当你超出数组的最后一个元素时,next()返回false,使用这些迭代方法,PHP数组的内部实现就与你不相关了。
迭代器结合了封装和多态的面向对象设计原理。使用迭代器,可以对集合中的对象进行操作,而无需专门了解集合如何显现或者集合包含什么(对象的种类)。迭代器提供了不同固定迭代实现的统一接口,完全包含了如何操纵特定集合的详细信息,包括显示哪些项(过滤)及其显示顺序(排序)。
适用性:
- 访问一个聚合对象的内容而无需暴露它的内部细节。
- 需要为聚合对象提供多种遍历方式。支持以不同的遍历一个聚合对象,复杂的聚合可用多种方式进行遍历,迭代器模式使得改变遍历算法变得更容易,仅需要用一个不同的迭代器的实例代替原先的实例即可。你也可以自己定义迭代器的子类以支持新的遍历。
- 为遍历不同的聚合结构提供一个统一的接口。(即支持多态迭代)。迭代器简化了聚合的接口,有了迭代器的遍历接口,聚合本身就不再需要类似的遍历接口了。
- 在统一格局和上可以有多个遍历,每个迭代器保持自己的遍历状态,因此可以同时进行多个遍历。
- 在迭代器模式中,增加新的聚合类和迭代器类都很方便,无需修改原有代码,符合“开闭原则”(软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等等,应该在不修改现有代码的基础上,引入新功能。开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即修改原有的代码对外部的使用是透明的。)。
角色:
Iterator(抽象迭代器):迭代器定义访问和遍历元素的接口
ConcreteIterator(具体迭代器):具体迭代器实现迭代器Iterator接口,对该聚合遍历时跟踪当前位置。
Aggregate(抽象聚合类):聚合定义创建相应迭代器对象的接口
ConcreteAggregate(具体聚合类):替聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。
代码示例:
\Libs\Aggregate.php
<?php namespace Libs; abstract class Aggregate { protected $_objs; protected $_size; public function createIterator() { } public function getItem() { } public function getSize() { return $this->_size; } }
\Libs\ConcreteAggregate.php
<?php namespace Libs; class ConcreteAggregate extends Aggregate { public function __construct($count) { for($i=0;$i<$count;$i++){ $this->_objs[] = $i; } } public function createIterator() { return new ConcreteIterator($this); } public function getItem($idx=0) { if($idx < $this->getSize()){ return $this->_objs[$idx]; } else { return FALSE; } } public function getSize() { return count($this->_objs); } }
\Libs\Iterator.php
<?php namespace Libs; abstract class Iterator { protected $_ag; protected $_idx; public function first(){} public function next(){} public function isDone(){} public function currentItem(){} }
\Libs\ConcreteIteratorSort.php
<?php namespace Libs; class ConcreteIteratorSort extends Iterator { public function __construct($ag,$idx=0) { $this->_ag = $ag; $this->_idx = $idx; } public function first() { $this->_idx = 0; } public function next() { if($this->_idx < $this->_ag->getSize()){ $this->_idx++; } } public function isDone() { if($this->_idx == $this->_ag->getSize()){ return TRUE; } else { return FALSE; } } public function currentItem() { return $this->_ag->getItem($this->_idx); } }
\Libs\ConcreteIteratorUnSort.php
<?php namespace Libs; class ConcreteIteratorUnSort extends Iterator { public function __construct($ag,$idx=0) { $this->_ag = $ag; $this->_idx = $idx; } public function first() { $this->_idx = $this->_ag->getSize()-1; } public function next() { if($this->_idx >=0){ $this->_idx--; } } public function isDone() { if($this->_idx < 0){ return TRUE; } else { return FALSE; } } public function currentItem() { return $this->_ag->getItem($this->_idx); } }
\Libs\UseIterator.php
<?php namespace Libs; class UseIterator { public static function index() { $ag = new ConcreteAggregate(10); $it_sort = new ConcreteIteratorSort($ag); $it_sort->first(); for(;$it_sort->isDone()==FALSE;$it_sort->next()) { echo $it_sort->currentItem().'***'; } echo '<br/>'; $it_unsort = new ConcreteIteratorUnSort($ag); $it_unsort->first(); for(;$it_unsort->isDone()==FALSE;$it_unsort->next()) { echo $it_unsort->currentItem().'***'; } } }
调用代码
IMooc\UseIterator::index();
结果:
0***1***2***3***4***5***6***7***8***9*** 9***8***7***6***5***4***3***2***1***0***
推荐阅读>>