迭代器模式

迭代器模式

一、什么是迭代器模式?

迭代器模式(Iterator Design Pattern):提供一种方式来访问聚合里面的所有元素,而不暴露聚合对象的内部数据结构。

迭代器模式,也称为游标模式,主要用于遍历数据集合。

迭代器模式的几个特点:

  • 目的是为了遍历集合数据
  • 特点是可以避免集合的内部数据结构暴露,增加集合内部实现的灵活性

迭代器是为了遍历集合数据,所以一个完整的迭代器,肯定是包括集合和迭代器2部分。

迭代器模式,关注重点在于遍历数据,而不是按照什么顺序遍历。

比如说,集合里是按照字母顺序保存的,但使用迭代器遍历时,遍历顺序并不一定是按字母排序。

所以,迭代器并不一定按照结构遍历,而是主要为了遍历数据。

二、为什么要用迭代器模式?

2.1 想要遍历集合的所有数据

迭代器的目的就是为了遍历数据,所以是为了遍历集合,可使用迭代模式。

2.2 不想暴露集合内部数据结构

有些时候,会出现

  • 不想被人知道集合内部的数据结构
  • 或者可能会修改内部数据结构实现

的情况,这时就需要隐藏内部的数据结构实现。

但是又需要遍历数据,这个时候就可以提供一个迭代器接口给外面调用。

2.3 想要统一集合的遍历结构

假如有很多种集合类型,比如 List、Set、Map、Tree、Graph 等。

每种数据结构是不同的,在实际遍历时需要写的代码也不一样。

比如,遍历树的方式就有前序遍历、中序遍历、后序遍历等,代码都不同。

想要按照统一的方式遍历这些集合,就可以用迭代器来实现。

2.4 想要特殊的遍历方式

有时候,想要按照某种顺序去遍历集合中的数据,可以自定义迭代器是完成。

比如按照字母顺序遍历,按照添加顺序遍历,按照添加顺序逆序遍历等等。

这个时候,可以为不同的遍历方式提供不同的迭代器实现。

三、怎么用迭代器模式?

迭代器模式中的角色包括:

  • 迭代器(Iterator):定义了遍历集合数据的接口
  • 具体迭代器(ConcreteIterator):实现了迭代器接口的具体迭代器,和具体的集合数据结构绑定
  • 集合(Aggregate):集合接口,定了了创建迭代器的接口
  • 具体集合(ConcreteAggregate):实现了集合接口的具体集合,提供属于自己的迭代器实现

迭代器模型结构:

迭代器模型结构

示例程序结构:

迭代器模型结构

迭代器(Iterator):

1
2
3
4
public interface Iterator<T> {
boolean hasNext();
T next();
}

集合(Aggregate):

1
2
3
public interface Aggregate<T> {
Iterator<T> iterator();
}

具体集合(ConcreteAggregate):

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class BookShelf implements Aggregate<Book> {

private Book[] books;
private int last = 0;

public BookShelf(int maxSize) {
this.books = new Book[maxSize];
}

public Book getBookAt(int index) {
return books[index];
}

public void appendBook(Book book) {
sortInsert(book);
}

public int getLength() {
return last;
}

private void sortInsert(Book book) {
int index = last;
for (; index > 0; index--) {
Book b = books[index - 1];
if (book.getName().compareTo(b.getName()) <= 0) {
break;
}
books[index] = b;
}
books[index] = book;
last++;
}

@Override
public Iterator<Book> iterator() {
return new BookShelfIterator(this);
}

}

具体迭代器(ConcreteIterator):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class BookShelfIterator implements Iterator<Book> {

private BookShelf bookShelf;
private int index;

public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
index = 0;
}

@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}

@Override
public Book next() {
return bookShelf.getBookAt(index++);
}
}

四、迭代器模式有什么优缺点?

优点:

  • 统一集合的遍历方式,特别是对于复杂结构来说更友好
  • 集合与迭代分离,耦合性低,很方便扩展迭代器
  • 隐藏集合的数据结构,提高集合内部实现的灵活性

缺点:

  • 客户端只能调用已有的迭代器,集合实现者需提供足够的迭代器实现
  • 迭代器增加了类的数量,在一定程度上增加了程序的复杂性

五、实际场景

  • JDK 中的集合类,基本都实现了 Iterator 迭代器
  • ArrayList 中提供了正序和逆序2种迭代器
  • LinkedHashMap 提供了按照添加顺序遍历的迭代器接口
作者

jiaduo

发布于

2022-01-21

更新于

2023-04-03

许可协议