参考了https://blog.csdn.net/lierming__/article/details/79620577的代码,图片和基本讲解(懒得打了)
都来自于《图解设计模式》——结城浩 著
Iterator模式
- Iterator在英文中有反复做某事的意思,Iterator模式用于在数据集合中按照顺序遍历集合。
- 迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
示例程序
这段程序的作用是将书(Book)放到书架(BookShelf)上,并将书名按顺序显示出来。
示例程序的示意图:
示例程序的类图:
Aggregate 接口:
是所要遍历的集合的接口。实现了该接口的类将成为一个可以保存多个元素的集合
/*
* 该接口中声明的方法只有一个-----iterator 方法。该方法会生成一个用于
* 遍历集合的迭代器
*/
public interface Aggregate {
public abstract Iterator iterator();
}
Iterator 接口:
Iterator接口用于遍历集合中的元素
/*
* 该接口用于遍历集合中的元素,其作用相当于循环语句中的循环变量
*/
public interface Iterator {
public abstract boolean hasNext(); //判断是否存在下一个元素的hasNext 方法 ,该方法主要用于循环终止条件
public abstract Object next(); //获取下一个元素的 next 方法
}
Book 类:
是BookShelf的成员变量,BookShelf知道他
public class Book {
private String name; //书名
public Book(String name){
this.name = name;
}
//获取书的名字
public String getName(){
return name;
}
}
BookShelf 类:
表示书架的类,由于需要作为集合进行处理,所以实现了Aggregate接口,并且实现了Aggregate接口的iterator方法。
public class BookShelf implements Aggregate{
private Book[] books;
private int last = 0; //书架上书的数量
public BookShelf(int maxsize){ //生成 BookShelf 实例时指定 books 数组的大小
this.books = new Book[maxsize];
}
public Book getBookAt(int index){ //获取书架上指定位置的书籍
return books[index];
}
public void appendBook(Book book){ //往书架上添加书籍
this.books[last] = book;
last++;
}
public int getLength(){ //获取书架上目前有多少本书
return last;
}
//获取遍历该书架的 Iterator 实例。当想在外部遍历书架时,就会调用该方法
public Iterator iterator(){
return new BookShelfIterator(this);
}
}
iterator()
方法会生成并返回BookShelfIterator类的实例作为BookShelf类对应的迭代器
BookShelfIterator 类:
public class BookShelfIterator implements Iterator{
private BookShelf bookShelf; //所要遍历的书架
private int index; //表示迭代器当前所指向的书的下标
public BookShelfIterator(BookShelf bookShelf){
this.bookShelf = bookShelf;
this.index = 0;
}
/*
* hasNext () 方法会判断书架中还有没有下一本书,如果有就返回 true ,
* 如果没有就返回 false 。而要知道书架中有没有下一本书,可以通过比较index
* 和书架中书的总册数(bookShelf.getLength())来判断。
*
*/
public boolean hasNext(){
if(index < bookShelf.getLength()){
return true;
}else{
return false;
}
}
/*
* next() 方法会返回迭代器当前所指向的书(Book 的实例),并让迭代器指向下一本书。
*
*/
public Object next(){
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
BookShelf类需要发挥迭代器的作用,所以实现了Iterator接口。
Main 类:———->测试程序
public class Main {
public static void main(String[] args){
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Around the World in 80 Days"));
bookShelf.appendBook(new Book("Bible"));
bookShelf.appendBook(new Book("Cinderella"));
bookShelf.appendBook(new Book("Daddy-Long-Legs"));
Iterator it = bookShelf.iterator();
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(book.getName());
}
}
}
运行结果
Iterator 模式中的登场角色
- Iterator (迭代器)
该角色负责定义按顺序逐个遍历元素的接口(API) 。在示例程序中,由 Iterator
接口扮演这个角色,它定义了 hasNext 和 next 两个方法。其中,hasNext 方法用
于判断是否存在下一个元素, next 方法用于获取该元素。 - ConcreteIterator (具体的迭代器)
该角色负责实现 Iterator 角色所定义的接口(API)。在示例程序中,BookShelfIterator 类扮演这个角色。该角色中包含了遍历集合所必需的信息。在示例程序中,BookShelf 类的实例保存在 bookShelf 字段中,被指向的书的下标保存 在 index 字段中。 - Aggregate(集合)
该角色负责定义创建 Iterator 角色的接口(API)。这个接口是一个方法,会创建出
“按顺序访问保存在我内部元素的人”。在示例程序中,由Aggregate 接口扮演这个角色,它里面定义了 iterator 方法。 ConcreteAggregate (具体的集合)
该角色负责实现 Aggregate 角色所定义的接口(API) 。它会创建出具体的 Iterator角色,即 ConcreteIterator 。在示例程序中,由BookShelf 类扮演这个角色,它实现了 iterator 方法。要点
为何要用Iterator模式,而不用简单的foreach循环来遍历呢?
Iteraror模式是将遍历和实现分离开来的
看以下代码
while(it.hasNext()){
Book book = (Book)it.next();
System.out.println(book.getName());
如果你想用for each循环来遍历,是一定要用到bookshelf的,实现如下
Book[] b = BookShelf.books;
for( book c: b){
System.out.println(c.getName());
}
如果你不用数组来管理Book,而是用别的集合,以上代码会怎样呢?
- 而Iterator模式的while循环并不依赖于BookShelf的实现,只要BookShelf实现Aggregate接口,能正确的返回Iterator实例(即hasnext和next都正常),即使不修改while的代码,也可以正常工作。
- 设计模式的作用就是帮助我们编写可复用的类。所谓“可复用”,就是指将类实现为“组件”,当一个组件发生改变时,不需要对其他的组件进行修改或是只需要很小的即可应付。
这也就是为什么在示例程序中Iterator方法返回的是Iterator而不是BookShelfIterator类型了。
难以理解抽象类和接口——–>引入抽象类和接口是为了降低耦合度
如果只是用具体的类来解决问题,很容易导致类之间的强耦合,这些类也难以作为组件被再次利用。为了弱化类之间的强耦合,进而使得类更加容易作为组件被再次利用,我们需要 引入抽象类和接口。
容易弄错“下一个”
在Iterator 模式的实现中,next 方法是 “返回当前的元素,并指向下一个元素”
还容易弄错“最后一个”
hasNext 可以理解成:“确认接下来是否可以调用 next 方法”的方法就可以了。
多个Iterator
“将遍历功能置于 Aggregate 角色之外 ”是 Iterator 模式的一个特征。
迭代器种类的多种多样
在示例程序中展示的 Iterator 类只是很简单地从前往后遍历集合。其实,遍历的方法有是多种多样的。**** 从最后开始向前遍历 **** 既可以从前向后遍历,也可以从后往前遍历(既有 next 方法也有 previous 方法) **** 指定下标进行“跳跃式”遍历
即,根据你的基本思想可以自己写Iterator接口,然后在ConcreteAggregate中具体实现,(具体怎么实现,什么算法都可以),这也体现了Iterator模式将遍历和实现分离开来的思想
总结:简单地说,迭代器就是一个用于对集合进行遍历的实现,优点在于,实现和遍历分离,不在乎容器内部原理(采用数组啊还是哈希表啊blabla)。