目录
[TOC]
什么是迭代器模式
迭代器模式是一种行为设计模式,能在不暴露集合底层表现形式(列表、栈和树等)的情况下便利集合中的所有元素
应用场景
- 当需要为聚合对象提供多种遍历方式时
- 当需要为遍历不同的聚合结构提供一个统一的接口时
迭代器设计模式类图

迭代器中的角色
- Iterator(迭代器):这个接口负责定义按顺序遍历元素的接口。其中hasNext负责判断是否还存在下一个元素,next方法用于获取该元素并将元素指针后移。
- ConcreteIterator(具体的迭代器):该类负责实现Iterator所定义的接口,同时包含遍历集合所必要的信息。在此示例中,BookShelf类的实例保存至bookShelf中,指向当前书的下标保存在index中。
- Aggregate(集合):实现该接口的类都需要实现获取Iterator的方法
- ConcreteAggregate(具体的集合):该类负责具体实现Aggregate所定义的方法。在该示例中由BookShelf负责承担此功能。
代码
未使用迭代器
在Java中想要遍历一个arr中的所有元素时,我们可以使用for循环来遍历整个列表
1 2 3 4
| List<String> items = new ArrayList<>(); for (int i = 0; i < items.size(); i++) { System.out.println(items.get(i)); }
|
这显然是一种很自然的做法,但是若此时用于存储元素的底层数据结构发生变化,我们就需要根据不同的数据结构实现不同的遍历方式。此时的我仅仅作为服务的调用者,这显然给我带来的不必要的负担。因为我只是想要遍历一遍所有元素,但是我却需要深入了解服务开发者所使用的数据结构,并实现不同的遍历逻辑。
有没有一种方式可以让服务开发者实现一个易调用的接口,我只需要调用一个方法就可以完成元素的遍历。将这种思想抽象起来,便得到了迭代器模式。
使用迭代器
Iterator接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public interface Iterator<T> {
boolean hasNext();
T next(); }
|
BookShelfIterator
迭代器接口实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.xiaofei.iterator;
public class BookShelfIterator implements Iterator<Book>{ private BookShelf bookShelf; private int index = 0;
public BookShelfIterator(BookShelf bookShelf) { this.bookShelf = bookShelf; }
@Override public boolean hasNext() { return bookShelf.getLength() > index; }
@Override public Book next() { Book book = bookShelf.getBookAt(index); index++; return book; } }
|
Aggrate
获取迭代器
1 2 3 4 5 6 7
| public interface Aggregate<T> {
public Iterator<T> getIterator(); }
|
BookShelf
获取迭代器接口实现和添加额外需要使用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.xiaofei.iterator;
import java.util.ArrayList; import java.util.List;
public class BookShelf implements Aggregate<Book> { List<Book> bookList = new ArrayList<>();
@Override public Iterator<Book> getIterator() { return new BookShelfIterator(this); }
public Integer getLength() { return this.bookList.size(); }
public void appendBook(Book book) { bookList.add(book); }
public Book getBookAt(Integer position) { return this.bookList.get(position); } }
|
Book类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @NoArgsConstructor @AllArgsConstructor public class Book { private String bookName; private Double price; private String author; }
|
测试
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void test(){ BookShelf bookShelf = new BookShelf(); bookShelf.appendBook(new Book("文城", 55.0,"余华")); bookShelf.appendBook(new Book("机器学习", 63.0,"周志华")); bookShelf.appendBook(new Book("统计学习方法", 82.0,"李航"));
Iterator<Book> iterator = bookShelf.getIterator(); while (iterator.hasNext()){ Book book = iterator.next(); System.out.println("book = " + book); } }
|

总结
迭代器模式是一种行为设计模式,它让你能在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一。
迭代器模式的主要思想是将集合的遍历行为抽取为单独的迭代器对象。除实现自身算法外,迭代器还封装了遍历操作的所有细节,比如当前位置和末尾剩余元素的数量、同时还有提供一个获取集合元素的基本方法。客户端可不断调用该方法直到它不返回任何内容 ( 已遍历所有元素 )、所有迭代器必须实现相同的接口 (只要有合适的迭代器,客户端代码就能兼容任何类型的集合或遍历算法)。