在java中容器有List、数组、Set、Map等等。这四种容器内部的组织方式都不一样,List是列表形式,Set是集合形式,Map是键值对形式。现在要去遍历一个容器里的内容,首先要了解内容在容器中的组织形式;在jdk中已经实现了List、Set、Map的迭代器,迭代器后,就不用去了解内容的组织形式了,直接用迭代器的 hasnext()和next()完成遍历。
现在来看开发中的一个实例,有一个列表List,存放的是一组Student对象,每个对象中都包含许多属性,这时要去遍历每个对象的某一个属性(比如说姓名),只有在知道姓名这个属性在对象中的形式才能完成遍历;但现在如果有一个专门用于遍历姓名这个属性的姓名迭代器(NameIterator),使用这个迭代器就可以轻松完成遍历,并且不用知道Student里的数据结构。
定义:让用户通过特定的接口遍历容器中的每一个元素而不用了解底层的实现
结构:
- 迭代器接口:定义一个遍历的接口,声明hasnext()和next()两个方法
- 具体迭代器:实现迭代器接口的hasnext()和next()两个方法
- 抽象容器:接口或者抽象类,声明iterator()方法
- 具体容器:容器的具体实现,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。
使用场景:
- 遍历一个聚合对象的内容而无须暴露它的内部表示。
- 需要为聚合对象提供多种遍历方式
- 为遍历不同的聚合结构提供一个统一的接口
UML类图:
下面就是迭代器模式的代码实现:
Containter(容器):
public interface Container {
void add(Student t);
Iterator mathPerformanceIterator();
Iterator nameItetator();
}
public class ConcreteContainter implements Container{
List<Student> list;
public ConcreteContainter(){
list = new ArrayList();
}
@Override
public void add(Student t){
list.add(t);
}
@Override
public Iterator mathPerformanceIterator() {
Iterator iterator = new MathPerformanceIterator(list);
return iterator;
}
@Override
public Iterator nameItetator() {
Iterator iterator = new NameIterator(list);
return iterator;
}
}
Iterator(迭代器):
public interface Iterator {
boolean hasnext();
Object next();
}
public class MathPerformanceIterator implements Iterator {
List<Student> list;
int i=0;
int size;
public MathPerformanceIterator(List<Student> list){
this.list = list;
size = list.size();
}
@Override
public boolean hasnext() {
if(i<size){
return true;
}else{
return false;
}
}
@Override
public Integer next() {
return list.get(i++).performance.math;
}
}
public class NameIterator implements Iterator {
List<Student> list;
int i=0;
int size;
public NameIterator(List<Student> list){
this.list = list;
size = list.size();
}
@Override
public boolean hasnext() {
if(i<size){
return true;
}else{
return false;
}
}
@Override
public String next() {
return list.get(i++).name;
}
}
两个辅助类:
public class Student {
public Student(String name,StudentPerformance studentPerformance,int age){
this.name = name;
this.performance = studentPerformance;
this.age = age;
}
String name;
StudentPerformance performance;
int age;
}
public class StudentPerformance {
public StudentPerformance(int math,int literature,int english){
this.math = math;
this.literature = literature;
this.english = english;
}
int math;
int literature;
int english;
}
Test:
public class Test {
public static void main(String[] args){
Container container = new ConcreteContainter();
container.add(new Student("tom",new StudentPerformance(80,80,90),19));
container.add(new Student("jack",new StudentPerformance(85,80,90),19));
container.add(new Student("tony",new StudentPerformance(81,80,90),19));
Iterator nameIterator = container.nameItetator();
Iterator mathPerformanceIterator = container.mathPerformanceIterator();
System.out.println("遍历Name:");
while (nameIterator.hasnext()){
System.out.print(nameIterator.next()+" ");
}
System.out.println();
System.out.println("遍历Math成绩:");
while (mathPerformanceIterator.hasnext()){
System.out.print(mathPerformanceIterator.next()+" ");
}
}
}
总结:
上面的代码分别实现了两个迭代器,一个用于遍历姓名,一个用于遍历数学成绩。上面这种写法不适用所有情况,因为写死了Student和StudentPerformance这两个对象,之所以这样写,是为了体现迭代器模式的精髓所在:用户使用对于迭代器就可以遍历想要的内容,而不用关心数据结构(Student,StudentPerformance)的实现。
平时开发中很少自己去自定义容器,jdk的List、Set、Map就能够满足绝大多数的需求了,jdk也帮我们把这些容器的Iterator都实现了,因此也不用去自己动手实现迭代器。
说到迭代器模式的缺点,对于一些简单的遍历,使用迭代器就会比较繁琐,有时候还不如使用for循环和get()方法来完成,平常开发中要做好这方面的权衡;还有一个缺点(说成特性可能比较恰当),迭代器遍历就像象棋中的卒一样,只能往前,无法后退。
参考:http://blog.csdn.net/zhengzhb/article/details/7610745
http://www.runoob.com/design-pattern/iterator-pattern.html