一、迭代子模式的核心思想
迭代子模式又称 Cursor 模式,是对象的行为模式。迭代子模式可以顺序地访问聚集中的对象而不必显露聚集的内部表象。
迭代子模式的作用是访问一个聚集,因此它需要包含两类对象。
- 聚集对象:聚集对象中提供了一系列的数据集合,它还需要提供访问该集合中元素的方法以供迭代器对象使用,如下图所示的 Collection是聚集对象的接口,MyCollection是具体的实现类。
- 迭代器对象:它提供了迭代聚集对象的功能,根据需要可以包括前移、后移、首、尾的名种方法,如下图所示的Iterator 就是一个迭代器接口,MyIterator 是一个具体的实现。
下面来看具体的实现。
(1) 集合接口 Collection.java 中首先需要定义一个取得迭代器对象的接口,并提供取得集合中某元素的方法 get(),以及取得集合大小的方法 size()。其源代码如下程序所示。
package behavior.iterator;
/**
* @author Minggg
* 集合接口
*/
public interface Collection {
// 取得迭代子
public Iterator iterator();
// 取得集合元素
public Object get(int i);
// 取得集合大小
public int size();
}
(2) 集合类 MyCollection.java提供了一个存放集合数据的数组,该数组可以是任意的集合类。这里我们使用了一个表示 26个英文字母的字符串数组作为演示。同时,该类需要实现其接口提供的3个函数。在创建迭代对象时,需要将当前对象this 作为参数传递给迭代器对象,以便迭代对象能够控制当前对象。其源代码如下程序所示。
package behavior.iterator;
/**
* @author Minggg
* 集合接口
*/
public class MyCollection implements Collection {
public String[] str= { "A","B","C","D","E", "F","G", "H","I","J","K", "L","M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
@Override
public Iterator iterator() {
return new MyIterator(this);
}
public Object get(int i) {
return str[i];
}
public int size(){
return str.length;
}
}
(3) 迭代子接口Iterator.java可以根据自身的需要提供各种迭代函数,例如下例中我们就提供了4种移动光标的函数,以及判断位置的函数。其源代码如下程序所示。
package behavior.iterator;
/**
* @author Minggg
* 迭代子接口
*/
public interface Iterator {
// 前移
public Object previous();
public boolean hasPrevious();
// 后移
public Object next();
public boolean hasNext();
// 第一个
public Object first();
public boolean isFirst();
// 最后一个
public Object last();
public boolean isLast();
}
(4) 迭代子 MyIterator.iava拥有一个对Collection对象的引用,并在具体的实现中通过该对象的引用进行集合数据的查询。其源代码如下程序所示。
package behavior.iterator;
public class MyIterator implements Iterator {
private Collection collection;//集合对多
private int pos = -1;//默认位置
publie MyIterator(Collection collection) {
this.collection = collection;
}
// 第一个
public Object first(){
pos = 0;
return collection.get(pos);
}
// 是否第一个
public boolean isFirst() {
if (pos == 0){
return true;
} else {
return false;
}
}
// 最后一个
public Object last() {
pos = collection.size()-1;
return collection.get(pos);
}
// 是否最后一个
public boolean isLast() {
if(pos == collection.size()-1){
return true;
} else {
return false;
}
}
// 后移
public Object next(){
if (pos < collection.size()-1){
pos ++;
}
return collection.get(pos);
}
// 后移
public boolean hasNext(){
if (pos < collection.size() - 1) {
return true;
} else {
return false;
}
}
// 前移
public Object previous() {
if(pos > 0) {
pos --;
}
return collection.get(pos);
}
// 前移
public boolean hasPrevious() {
if(pos > 0){
return true;
} else {
return false;
}
}
}
我们可以使用以上的集合类和迭代子编写调用代码。首先创建一个MyCollection集合对象collection,并根据该对象取得迭代子it,这样,就可以使用it来迭代査询 collection中的数据了。其源代码如下程序所示。
package behavior.iterator;
public class Test {
public static void main(String[] args) {
Collection collection = new MyCollection();
Iterator it = colleetion.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行该程序就会迭代输出集合中的各个字母:
A
B
...
Y
Z
二、何时使用迭代子模式
由此可见,迭代子的作用就是用来方便地查询一个集合中的数据。凡是有聚集数据存在的地方,都可以使用迭代子模式来进行数据迭代。
使用迭代子模式有以下优点:
- 迭代子模式简化了聚集的界面。
- 因为每一个聚集对象可以有多个迭代子对象,每个迭代子状态是独立的。
- 由于遍历算法被封装在迭代子角色里面,因此迭代的算法可以独立于聚集对象。
但是,迭代子模式给客户端一个聚集被顺序化的感觉,而且它给出的聚集元素没有类型特征。
三、Java中的应用–Java集合类选代子Iterator和Enumeration
迭代子应用在存在大量集合对象的场景下。在Java API中,为我们提供了功能强大的集合类体系,如下图所示。
这么多纷繁复杂的类!其中常用类有 Vector、Hashtable、LinkedList、ArrayList 等。从这么多相似的名字中,似乎很难区分它们。理解它们的关键是从最顶层的接口看起,共有两个顶层的接口类。
- 集合类 Collection:代表多个对象的集合,根据其子接口,又可以分为三大类。
- Queue:队列类,先进先出的队列。
- List:列表类,其中的元素是有序的,且允许元素重复。
- Set:集合类,其中的元素是有序或无序的,且不允许元素重复。
- 映射类 Map:存储多个键值对。
其中的 List、Set、Map 都有一系列的实现类。
所有的这些集合类,都可以转化为最顶层的Iterator 和 Enumeration对象,它们就是其他所有集合类的迭代子。这两个接口是特殊的数据操作接口,Iterator用于进行数据迭代,称做迭代器;Enumeration用于进行数据枚举,称做枚举。
1.枚举(Enumeration)接口
枚举(Enumeration)接口是从以前版本遗留下来的。Enumeration接口定义了可以对一个对象的类集中的元素进行枚举(一次获得一个)的方法。这个接口尽管没有被据弃,但已经被Iterator所替代。Enumeration对新程序来说是过时的,然而它仍被几种从以前版本遗留下来的类(例如Vector、Hashtable 和 Properties)所定义的方法使用,被几种其他的 API类及被目前广泛使用的应用程序所使用。
Enumeration指定下面的两个方法:
- boolean hasMoreElements();
- Obiect nextElement();
执行后,当仍有更多的元素可提取时,hasMoreElement()方法一定返回true。所有元素都被枚举了,则返回 false。nextElement()方法将枚举中的下一个对象作为一个类属性 Object的引用而返回也就是每次调用 nextElement()方法获得枚举中的下一个对象,调用例程必须将那个对象置为包含在枚举内的对象类型。
对于 Enumeration 可以以 Vector 为例。Vector 里有很多对象,如果你要查看其中的所有对象,一个办法是用 Vector 的 get(int index)方法,不过这样效率比较低,另外一个方法是用 Vector 的 elements(方法返回一个 Enumeration 对象,用 Enumeration 的 hasMoreElements()方法向下移动并判断当前位置是否有对象,有则用nextElement()方法返回这个对象。
例如,打印vector v中的所有对象:
Enumeration e = v.elements();
while(e.hasMoreElements()) {
System.out.println(e.nextElement());
}
2.迭代器(Iterator)接口
另外还有个Iterator 接口,与Enumeration差不多,不过名称比较短,通常推荐用Iterator 对Collection集合进行迭代。迭代器代替了JavaCollections Framework中的 Enumeration。Collection 接口中定义了 iterator()方法,用于返回在此 collection 的元素上进行迭代的迭代器。
迭代器提供了如下3个方法供Collection类的实例使用:
boolean hasNext(); // 如果仍有元素可以迭代,则返回 true
E next(); // 返回选代的下一个元素
void remove(); // 从选代器指向的collection中移除迭代器返回的最后一个元素
例如,要输出Vector对象vect的迭代器,可以这样写:
Iterator it = vect.iterator(); // 得到迭代器对象
while (it.hasNext()) { //迭代循环
Object obj = it.next(); // 取得对象
}