GOF设计模式——Iterator模式
Iterator,自然而然想到的是用于集合遍历的迭代器Iterator,没错Iterator模式就是指这个意思。
先来看一段代码:
int[] array = new int[10];
for(int i = 0; i<array.length; i++){
System.out.println(array[i]);
}
上面是编程里面很常见的遍历数组的用法,假如我不直接操作array对象,然后将用于表示下标的 i 抽象化,通用化,将遍历的动作交给迭代器,那么这种模式就叫做Iterator模式。
举一个示例,有一个书架和一些书,每一本书作为一个个体(实例),书架可以理解为这些个体的集合。
介绍一下上面的各个“东西”:
Aggregate:一个集合接口,凡是实现这个接口的iterator方法,就具有集合的功能;
Iterator:一个具有遍历功能的迭代器接口,里面定义了迭代需要的方法;
BookShelf:集合的具体实现类;
BookShelfIterator:迭代器接口的具体实现类;
Book:个体类。
1、Aggregate接口定义:
public interface Aggregate{
public abstract Iterator iterator();
}
2、Iterator接口:
public interface Interator{
public abstract boolean hasNext();
public abstract Object next();
}
里面很简单,只定义了两个方法:hasNext和next。使用过集合迭代器的小伙伴都知道,hasNext用于判断是否存在元素,next获取当前元素的同时,将下标指向下一个元素。
3、BookShelf类定义
public class BookShelf implement Aggregate{
private Book[] books;
private int last = 0;
public BookShelf(int maxsize){
books = new Book[maxsize];
}
public Book getBookAt(int index){
return books[index];
}
public void appendBook(Book book){
books[last] = book;
last++;
}
public int getLength(){
return last;
}
public Iterator iterator(){
return new BookShelfIterator(this);
}
}
构造方法根据参数创建指定大小的Book数组,appendBook用于给数组添加元素,getLength获取当前数组长度(正确来说是当前数组最后一个元素的下标+1),另外,还实现了Aggregate的抽象方法iterator(),上面也提及到,只要一个类实现了Aggregate接口,就具有集合的功能,即遍历功能,在这里,只是用于创建迭代器的实现类BookShelfIterator,遍历的具体功能交给BookShelfIterator实现类去实现。
4、BookShelfIterator类定义
public class BookShelfIterator implements Iterator{
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf){
this.bookShelf = bookShelf;
this.index = 0;
}
public boolean hasNext(){
if(index < bookShelf.getLength()){
return true;
} else {
return false;
}
}
public Object next(){
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
很简单,构造方法里将BookShelf对象作为参数,当前属性指向BookShelf对象,用于操作获取BookShelf元素,以及BookShelf长度。hashNext的实现逻辑只是对BookShelf对象的长度做一个判断,如果当前下标小于BookShelf长度,那么就返回true,否则,返回false。next方法,除了返回指定下标元素之外,还将下标向后推移了一位,即next实现了两个功能。
5、Book类定义
public class Book{
private String name;
public Book(String name){
this.name = name;
}
public String getName(){
return name;
}
}
至于测试方法,这里不写出来了。
我们就会发现,开头那段for代码里面的i++,就相当于next()方法里面的index++操作,都是用于指向下一位元素。上面代码的实现效果相当于ArrayList,不过BookShelf这个集合类这样子写,是会出问题的,ArrayList对象是可以“无限”添加元素,但是BookShelf最大只能添加maxsize个元素,所以可以进行改进。
改进后的BookShelf类:
public class BookShelf implement Aggregate{
private List Books;
public BookShelf(int initialsize){
books = new ArrayList(initialsize);
}
public Book getBookAt(int index){
return (Book)books.get(index);
}
public void appendBook(Book book){
books.add(book);
}
public int getLength(){
return books.size();
}
public Iterator iterator(){
return new BookShelfIterator(this);
}
}
至于为什么要使用Iterator呢?一个重要原因是,可以将遍历与实现分离开来。对BookShelf对象进行遍历的时候,会用到下面代码:
Iterator it = bookShelf.iterator();
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(book.getName());
}
遍历的过程,根本没有使用过BookShelf类的方法,完全不需要理会BookShelf的实现,也不知道BookShelf怎么实现,但是Iterator知道,所以只需要调用Iterator的方法就可以实现遍历BookShelf集合的效果。这样设计的好处就是,可以根据的实际业务需求来增加遍历的功能,使得原有的代码不改动或少改,达到一个低耦合的效果。