迭代器模式其实还是非常好理解的,因为我们无时无刻都在使用着迭代器模式,当我们用foreach语法遍历List集合,Set集合的,Map集合的时候,无形中就用到了java实现的迭代器,比如这样:
public static void main(String[] args) {
List<String> list = new ArrayList<String>(Arrays.asList("张三","李四","王五"));
for (String s : list) {
System.out.print(s+",");
}
System.out.println();
//foreach实现原理相当于直接使用下面的代码
Iterator<String> iterator = list.iterator();
while( iterator.hasNext() ){
String s = iterator.next();
System.out.print(s+",");
}
}
现在我们知道了在遍历List的集合的时候,是先通过调用它的iterator()方法拿到迭代器,再去借助于迭代器进行数据遍历, 接下来就去看看Iterator接口有些什么!
/**
* An iterator over a collection. {@code Iterator} takes the place of
* {@link Enumeration} in the Java Collections Framework. Iterators
* differ from enumerations in two ways:
*/
public interface Iterator<E> {
//是否有下一个元素
boolean hasNext();
//取出下一个元素
E next();
//移除一个元素
void remove();
}
我们去看源码可以发现,Set,List接口都间接继承了Iterable接口,所以所有的List和Set集合都提供了Iterator()方法用来获取迭代器,正因如此,编译器在解析foreach语法的时候,就可以放心的转换成调用要遍历的对象的iterator()方法来进行遍历了;
那么java为什么要设计一个迭代器来进行数据遍历呢?为什么不直接在具体实现类中直接提供遍历方法呢? 我们用代码来说话吧,对比不用迭代器和使用迭代器的区别,你就完全明白了!
场景假定: 假设我们的学校现在有两个班级,而某一天两个班级合并了,此时需要清点人数...我们先来看一看代码
/**高年级一班,一班的学生是用数组来存储的,为了代码简介,
我就不写增加学生方法...移除学生方法...
也不去建立一个学生类了,直接用String代表一个学生!
*/
public class GradeOne{
private String [] students;
public GradeOne() {
int length = 5;
students = new String[length];
for(int i = 0 ; i < length ; i++){
students[i] = "李寻欢"+i;
}
}
//提供获取学生的方法
public String[] getStudents() {
return students;
}
}
/**年级二班是用List来存储学生的*/
class GradeTwo {
private List<String> students;
public GradeTwo() {
students = new ArrayList<String>();
for (int i = 0; i < 8; i++) {
students.add("乔峰"+i);
}
}
public List<String> getStudents() {
return students;
}
}
/**老师类*/
class Teacher{
/***
* 该老师要清楚的知道自己班级中的所有人,并能说出来
*/
public void print(){
//此时此刻,由于先前三个班级的代码是不同的人写的,
//所以拥有不同的数据结构,这时候老师就有点痛苦了...
//我们接着往下看...
GradeOne gradeOne = new GradeOne();
String [] oneStudents = gradeOne.getStudents();
for (int i = 0; i < oneStudents.length; i++) {
System.out.print( oneStudents[i]+"," );
}
GradeTwo gradeTwo = new GradeTwo();
List<String> twoStudents = gradeTwo.getStudents();
for (int i = 0; i < twoStudents.size(); i++) {
System.out.print( twoStudents.get(i)+"," );
}
}
}
我们看看上面的Teacher类代码,老师要对原本两个班级合并成的一个班级里的人数进行清点,但却发现开发这两个个班级类的程序猿所使用的数据结构都不相同,所以老师类只好对每种结构进行不同方式的遍历... 如果继续有不同数据结构的班级融入进来...代码又得改!老师类希望的是,它不用去管底层f封装好的数据结构,它急切希望有一种能对各种数据结构都能进行遍历的统一的方法!由此,迭代器模式诞生!
让我们来改动一下代码吧!
先抽象增加迭代器接口:
/**一个遍历数据统一的接口*/
interface Iterator<E>{
//是否有下一个元素
boolean hasNext();
//取得下一个元素
E next();
}
/**一旦实现此接口,代表是支持迭代器遍历的*/
interface Iterable<E>{
Iterator<E> iterator();
}
/**高年级一班,一班的学生是用数组来存储的,为了代码简介,
我就不写增加学生方法...移除学生方法...
也不去建立一个学生类了,直接用String代表一个学生!
*/
public class GradeOne implements Iterable<String>{
private String [] students;
public GradeOne() {
int length = 5;
students = new String[length];
for(int i = 0 ; i < length ; i++){
students[i] = "李寻欢"+i;
}
}
//用匿名内部类实现返回一个迭代器
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
//记录当前读取的元素下标
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex<students.length;
}
@Override
public String next() {
return students[currentIndex++];
}
};
}
}
/**年级二班是用List来存储学生的*/
class GradeTwo implements Iterable<String>{
private List<String> students;
public GradeTwo() {
students = new ArrayList<String>();
for (int i = 0; i < 8; i++) {
students.add("乔峰"+i);
}
}
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex<students.size();
}
@Override
public String next() {
return students.get(currentIndex++);
}
};
}
}
/**老师类*/
class Teacher{
/***
* 该老师要清楚的知道自己班级中的所有人,并能说出来
*/
public void print(){
GradeOne gradeOne = new GradeOne();
GradeTwo gradeTwo = new GradeTwo();
print(gradeOne.iterator());
print(gradeTwo.iterator());
}
public void print( Iterator iterator ){
while( iterator.hasNext() ){
System.out.println( iterator.next() );
}
}
}
public class Test {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.print();
}
}
输出:
*******************************************************************
李寻欢0,李寻欢1,李寻欢2,李寻欢3,李寻欢4,乔峰0,乔峰1,乔峰2,乔峰3,乔峰4,乔峰5,乔峰6,乔峰7,
*******************************************************************
上面就是我们自己实现的迭代器,当然它很简陋,但足以用来说清迭代器模式了..感兴趣可以去看看java中List,Set等等集合的迭代器实现方式;
我们对比两断代码发现,实现了迭代器后,代码变得简洁,无论底层是什么数据结构,客户端都能用一致的方法来进行遍历了!所以我们可以得出结论,迭代器模式的作用就是为所有不同数据结构的集合提供一个统一的遍历方式!