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;}//判断当前是否遍历到结尾,到结尾返回truepublic 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)模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。迭代器模式在访问数组、集合、列表等数据时,尤其是数据库数据操作时,是非常普遍的应用,但由于它太普遍了,所以各种高级语言都对它进行了封装,所以反而给人感觉此模式本身不太常用了。
