概述
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
案例
黑枣电视公司的在生产的电视机,使用遥控器[后一个]和[前一个]按钮调节频道。当按下[后一个]按钮时,将切换到下一个预置的频道。想象一下在陌生的城市中的旅店中看电视。当改变频道时,重要的不是几频道,而是节目内容。如果对一个频道的节目不感兴趣,那么可以换下一个频道,而不需要知道它是几频道。。
分析OOA:
迭代器模式是为容器而生。很明显,对容器对象的访问必然涉及到遍历算法。这里有两个方案:
方案一、可以将遍历方法塞到容器对象中去
方案二、容器不去提供什么遍历算法,让使用容器的人自己去实现去吧。
方案一中,容器承受了过多的功能,它不仅要负责自己“容器”内的元素维护(添加、删除等等),而且还要提供遍历自身的接口;而且由于遍历状态保存的问题,不能对同一个容器对象同时进行多个遍历。方案二倒是省事又提高了容器的内聚能力。
设计OOD:
<UML>
<说明>
- 迭代器角色(ChanelIterator):迭代器角色负责定义访问和遍历元素的接口。
在本例中ChanelIterator定义迭代器必须实现moveText\first\next\current方法 - 具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。
TvChannelIterator为电视频道的具体迭代实现类,封装了具体的迭代算法。 - 容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。
在本例中ChannelList为容器角色,定义了getIterator以使容器角色取得一个具体迭代器角色实例。 - 具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。
在本例中TvChannellist为具体容器角色
编程 OOP:
<代码>
//迭代器角色(Iterator)
interface ChannelIterator
{
/**
* 判断可否向下移动游标
* @abstract
* @return boolean
*/
public function moveNext();
/**
* 将游标置0
* @abstract
* @return none
*/
public function first();
/**
* 向前移动游标
* @abstract
* @return none
*/
public function next();
/**
* 取得当前游标所指数据项
* @abstract
* @return none
*/
public function current();
}
//具体迭代器角色(Concrete Iterator)
class TvChannelIterator implements ChannelIterator
{
private $list = null;
private $index = 0;
public function __construct($list){
$this->list = $list;
$index = 0;
}
public function moveNext()
{
if($this->index < count($this->list)){
return true;
}else{
return false;
}
}
public function first()
{
$this->index = 0;
}
public function next()
{
if( $this->index < count($this->list)) $this->index++;
}
public function current()
{
return $this->list[$this->index];
}
}
//容器角色(Container)
interface ChannelList
{
/**
* 取得一个具体迭代器角色实例
* @abstract
* @return mixed 具体迭代器角色实例
*/
public function getIterator();
}
//具体容器角色(Concrete Container)
class TvChannellist implements ChannelList
{
private $list;
public function __construct()
{
$this->list = array(
'0' => '北京台',
'1' => '山东台',
'2' => '湖南台',
'3' => '凤凰台',
'4' => '河北台'
);
}
public function getIterator()
{
return new TvChannelIterator($this->list);
}
public function getLength()
{
return count($this->list);
}
public function getChannel($index = 0)
{
return $this->list[$index];
}
}
测试用例Test Case:
<代码>
class testDriver
{
public function run()
{
$channels = new TvChannellist();
$iterator = $channels->getIterator();
while($iterator->moveNext()){
echo "频道:". $iterator->current()."\n";
$iterator->next();
}
}
}
$test = new testDriver();
$test->run();
<输出>
小结:
面向对象设计原则中有一条是类的单一职责原则,所以我们要尽可能的去分解这些职责,用不同的类去承担不同的职责。Iterator模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明的访问集合内部的数据。
【常用情境】:
1.访问一个聚合对象的内容而无需暴露它的内部表示。
2.支持对聚合对象的多种遍历。
3.为遍历不同的聚合结构提供一个统一的接口(即, 支持多态迭代)。
【优点】
支持以不同的方式遍历一个容器角色。根据实现方式的不同,效果上会有差别。
2. 简化了容器的接口。
3. 对同一个容器对象,可以同时进行多个遍历。因为遍历状态是保存在每一个迭代器对象中的。
【缺点 】
由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
将容器的内部细节向迭代器暴露无遗
*********************转载请注明来源********************
* 作者:叶文涛
* 标题:Php设计模式之迭代器模式Iterator Pattern(一)
* 参考:
*《Head First设计模式》Eric Freeman等著
*《PHP设计模式》Aaron Saray等著,梁志敏等译(PS:翻译的是狗屁水平)
* Java设计模式之迭代器模式 http://www.51cto.com/specbook/11/9578.htm
* .NET设计模式(18):迭代器模式(Iterator Pattern)http://www.cnblogs.com/Terrylee/archive/2006/09/16/Iterator_Pattern.html
*********************转载请注明来源********************