迭代器模式
提供一种方法顺序访问一个聚合对象的各个元素,而又不暴露其内部的表示。迭代器模式在GOF95中分类为行为模式,别名游标(Cursor)模式。
- 一般集合类具有共同的接口Aggregate,例如java.util.Collection,该接口定义了创建迭代器的方法
- 迭代器接口包含判断是否有更多元素、执行遍历、执行删除的方法。某些迭代器可能支持双向遍历,例如 java.util.ListIterator
- 每一个具体集合类都能返回一个具体的迭代器,用于遍历
在面向对象语言中,集合具有多种形式,例如数组、元组、堆栈、链表或者散列表,很多时候需要对集合的元素进行遍历,如果集合类型实现迭代器模式,那么客户代码只需要通过迭代器即可遍历所有元素,而不需要了解集合类本身的接口。
Java的集合框架包括多种List、Queue、Set、Map接口的实现,除了Map以外,其它接口均继承与Collection。Map也通过keySet()、entrySet()、values()等API对Collection接口形成依赖。
Collection接口继承于Iterable,后者定义了创建迭代器Iterator的方法,这正是电信的迭代器模式的应用。Java集合框架的类图如下:
从Java5开始,新的语法被引入,对迭代的统一支持被添加到语言的层次上了:
1 2 3 4 |
List<String> list = new ArrayList<String>(); for(String el:list){ //新的集合遍历语法,亦支持数组 System.out.println(el); } |
ExtJS中有大量命名为 each() 的方法,例如:
1 2 3 4 5 |
Ext.each(); //迭代一个数组或者iterable对象 Ext.Object.each(); //迭代对象的所有属性 Ext.dom.CompositeElement.each(); //迭代DOM元素的集合 Ext.util.HashMap.each(); //迭代散列表的元素 Ext.util.AbstractMixedCollection.each(); //迭代混合集合的元素 |
这些方法都允许传入一个回调函数,由ExtJS框架对集合中没有元素执行这一回调。这本质上是一种迭代器模式,因为它提供了统一的遍历元素的接口。
C++的标准模板库也实现了迭代器模式,接口风格比较精炼但很不OO:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
vector<int> v; //在STL这里,迭代器更像一个哨兵(记号),而不是对象 for ( vector<int>::iterator it = v.begin(); it != v.end(); it++ ) cout << *it << endl; //解引用操作符用来获取当前迭代器对应的元素值 list<int> l; for ( list<int>::iterator it = l.begin(); it != l.end(); it++ ) ; map<int, string*> m; for ( map<int, string*>::iterator it = m.begin(); it != m.end(); it++ ) { it->first; //Key it->second;//Value } |
Python从语言层次上对迭代器模式做了很好的支持,只要对象实现 __iter__() 或者 __getitem__() 方法,即支持迭代:
1 2 3 4 5 6 7 8 |
for i in [1, 2, 3, 4]: # 遍历列表 print i, for c in "python": # 遍历字符串中的字符 print c for k in {"x": 1, "y": 2}: # 遍历字典的键 print k for line in open( "a.txt" ): # 遍历文件的行 print line |
__iter__() 方法的返回类型是 iterator ,该类型具有接口 next() 并且在没有更多元素时抛出 StopIteration() ,内置函数 iter() 用于自动调用 __iter__() :
1 2 |
it = iter( [1, 2, 3, 4, 5] ) it.next() |
- 集合类中创建迭代器的方法 createIterator() 是工厂方法模式的应用
- 迭代器模式常常与组合模式一起使用,组合模式是一种递归的、树状的数据结构,遍历某个节点时,通常会使用迭代器模式
Leave a Reply