说起遍历,我立马就想到for循环,增强for循环,foreach循环这类的循环遍历,这个不错,既然有这么方便的遍历,为什么我们还要学习Iterator这样的遍历呢?
一个重要的理由是:引入Iterator后可以将遍历和实现分离开来
此话怎讲?什么意思呢?
来说明这样的一个场景:
刚开始写程序时,我们用的是Array,我们自定义的时候指定大小,然后用for循环进行遍历的如火如荼,突然有一天,要求变了,数组大小可变,并且要求使用ArrayList来定义这个集合,那么是不是所有的原来定义为Array的集合都需要改变,并改变其遍历方式啊?这样是不是很麻烦了!
那么问题来了,有没有一种方法或者模式,将遍历和实现分开呢?上面的遍历和实现是耦合在一块的,通过for循环来实现遍历,将for循环绑定到遍历上,如果for循环没法实现了(比如上面,Array被ArrayList代替了,那么for循环的长度由length变为size()了),那么遍历就泡汤了。呵呵,当然有这种方法了,那就是Iterator方式了。
怎么把这遍历和实现分离开呢?请看下文详细分解
这里有四个角色,分别是Iterator,CustomeIterator,Aggregate,CustomeAggregate;四个角色,这四个角色对应的不同的用处,具体如下:
Itertor:这个角色是个接口,用来定义顺序逐个遍历元素的API,包含hasNext和next两个方法。
CustomeIterator:这个是实现Iterator的具体类,用来处理实际上的工作,包含了遍历集合必须的信息(需要遍历的集合以及集合对应的下标)
Aggregate:定义创建Iterator的接口API,
CustomeIterator:实现Aggregate接口并制定Iterator实现的具体类CustomeIterator,并将自己指定为CustimeIterator需要的集合
其类图如下所示:
下面是测试案例
1,java util 的Iterator类,这个来自于java.util.Iterator,
2,自定义的BookShelfIterator类
package ModelItertor; import java.util.Iterator; public class BookShelfIterator implements Iterator { private int index; private BookShelf bookShelf; public BookShelfIterator(BookShelf bookShelf){ this.bookShelf = bookShelf; this.index = 0; } public boolean hasNext() { return index<this.bookShelf.getLength(); } public Object next() { Book book = this.bookShelf.getBookAt(index); index++; return book; } }
3,Aggregate类
package ModelItertor; import java.util.Iterator; public interface Aggregate { public abstract Iterator iterator(); }
4,自定义的BookShelf类
package ModelItertor; import java.util.Iterator; public class BookShelf implements Aggregate { private Book[] books; private int last=0; public BookShelf(int maxsize){ this.books = new Book[maxsize]; } public Book getBookAt(int i){ if(i>=books.length){ return books[books.length-1]; } else{ return books[i]; } } public void appendBook(Book book){ books[last] = book; last++; } public int getLength(){ return this.last; } public Iterator iterator() { return new BookShelfIterator(this); } }
5,测试的main类
package ModelItertor; import java.util.Iterator; public class Main { public static void main(String[] args) { BookShelf bookShelf = new BookShelf(4); bookShelf.appendBook(new Book("A")); bookShelf.appendBook(new Book("B")); bookShelf.appendBook(new Book("C")); bookShelf.appendBook(new Book("D")); Iterator it = bookShelf.iterator(); while(it.hasNext()){ Book book = (Book)it.next(); System.out.println(book.getName()); } } }
最终结果
A
B
C
D
那么,还是最上面的问题,为什么搞这么复杂呢?
现在有这样的一个需求,书的数量是可变的,也就是集合由以前的Array变为ArrayList,那么,我们只需要修改一下CustomeAggrator类的实现规则即可,对Iterator的类根本不用做任何改变,改变后的BookShelf类如下
package ModelItertor; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class BookShelfList implements Aggregate { private List bookList; public BookShelfList(int size){ this.bookList = new ArrayList(size); } public Book GetBookAt(int i){ return (Book) bookList.get(i); } public Iterator iterator() { return new BookShelfListIterator(this); } public int getLength(){ return bookList.size(); } public void appendBook(Book book){ bookList.add(book); } }
测试main方法如下
package ModelItertor; import java.util.Iterator; public class Main { public static void main(String[] args) { BookShelfList booklist = new BookShelfList(2); booklist.appendBook(new Book("E")); booklist.appendBook(new Book("F")); booklist.appendBook(new Book("G")); booklist.appendBook(new Book("H")); Iterator it2 = booklist.iterator(); while(it2.hasNext()){ Book book = (Book)it2.next(); System.out.println(book.getName()); } } }