20.2迭代器模式
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
迭代器模式的使用场景:
- 当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。
- 你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。
也就是说,为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
现在高级编程语言如 C#、JAVA 等本身已经把这个模式做在语言中了。不管如何,学习一下GoF的迭代器模式的基本结构,还是很有学习价值的。研究历史是为了更好地迎接未来。
20.3迭代器实现
迭代器模式(Iterator)结构图
代码示例
Iterator迭代器抽象类
abstract class Iterator
{
abstract function First();
abstract function Next();
abstract function IsDone();
abstract function CurrentItem();
}
Aggregate聚集抽象类
abstract class Aggregate
{
abstract function CreateIterator();
}
ConcreteIterator具体迭代器类,继承Iterator
class ConcreteIterator extends Iterator
{
//定义一个具体聚集对象
private $aggregate = null;
private $current = 0;
//初始化时将具体的聚集对象传入
public function __construct($aggregate)
{
$this->aggregate = $aggregate;
}
//得到聚集的第一个对象
public function First()
{
return $this->aggregate[0];
}
//得到聚集的下一个对象
public function Next()
{
$ret = null;
$this->current ++;
if ($this->current < count($this->aggregate)) {
$ret = $this->aggregate[$this->current];
}
return $ret;
}
//判断当前是否遍历到结尾,到结尾返回true
public function IsDone()
{
return $this->current >= count($this->aggregate) ? true : false;
}
//返回当前的聚集对象
public function CurrentItem()
{
return $this->aggregate[$this->current];
}
}
ConcreteAggregate具体聚集类 继承Aggregate
class ConcreteAggregate extends Aggregate
{
private $items = array();
public function CreateIterator()
{
return new ConcreteIterator($this);
}
//返回聚集总个数
public function Count()
{
return count($this->items);
}
public function setItems($value)
{
$this->items[] = $value;
}
public function getItems()
{
return $this->items;
}
}
ConcreteIteratorDesc 反向遍历具体迭代器类,继承Iterator
class ConcreteIteratorDesc extends Iterator
{
private $aggregate = null;
private $current = 0;
public function __construct($aggregate)
{
$this->aggregate = $aggregate;
$this->current = count($this->aggregate) - 1;
}
public function First()
{
return $this->aggregate[$this->current];
}
public function Next()
{
$ret = null;
$this->current --;
if ($this->current >= 0) {
$ret = $this->aggregate[$this->current];
}
return $ret;
}
public function CurrentItem()
{
return $this->aggregate[$this->current];
}
public function IsDone()
{
return $this->current < 0 ? true : false;
}
}
客户端代码
public function iteratorImp()
{
$a = new ConcreteAggregate();
$a->setItems('大鸟');
$a->setItems('小菜');
$a->setItems('行李');
$a->setItems('老外');
$a->setItems('公交内部员工');
$a->setItems('小偷');
//此处切换遍历方式
$i = new ConcreteIterator($a->getItems());
//$i = new ConcreteIteratorDesc($a->getItems());
$i->First();
while (!$i->IsDone()) {
echo $i->CurrentItem() . '请买车票!' . PHP_EOL;
$i->Next();
}
}
运行结果
大鸟请买车票!
小菜请买车票!
行李请买车票!
老外请买车票!
公交内部员工请买车票!
小偷请买车票!
20.4.NET的迭代器实现(拓展)
.NET迭代器代码实现
IEumerator 支持对非泛型集合的简单迭代接口。
public function IEumerator
{
object Current
{
get;
}
boll MoveNext();
//恢复初始化指向的位置,该位置位于集合中第一个元素之前
void Reset();
}
IEnumerable 公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。
public interface IEnumerable
{
//返回一个循环访问集合的枚举数
IEumerator GetEnumerator();
}
foreach in应用代码。
static void Main(string[] args)
{
IList<string> a=new List<string>();
a.Add("大鸟");
a.Add("小菜");
a.Add("行李");
a.Add("老外");
a.Add("公交内部员工");
a.Add("小偷");
foreach (string item in a)
{
Console.WriteLine("{0} 请买车票!", item);
}
Console.Read();
}
foreach in 在编译器里做的工作。
IEnumerator<string> e = a.GetEnumerator();
while (e.MoveNext())
{
Console.WriteLine("{0} 请买车票!", e.Current);
}
foreach in 就是实现这两个接口来实际循环遍历。
总的来说,迭代器(Iterator)模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。迭代器模式在访问数组、集合、列表等数据时,尤其是数据库数据操作时,是非常普遍的应用,但由于它太普遍了,所以各种高级语言都对它进行了封装,所以反而给人感觉此模式本身不太常用了。