迭代器模式:统一遍历集合的方式
在软件开发中,我们经常需要处理各种集合对象,如数组、列表、树、图等。不同的集合数据结构有着不同的内部表示和遍历方式,这给客户端代码带来了复杂性。迭代器模式应运而生,它提供了一种统一的方法来顺序访问集合对象中的元素,而不需要暴露其底层实现。
什么是迭代器模式?
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
核心思想
迭代器模式的核心在于将遍历行为从集合对象中分离出来,抽象到一个独立的迭代器对象中。这样既简化了集合接口,又让客户端能够以统一的方式处理不同的集合结构。
模式结构
迭代器模式主要包含以下几个角色:
- Iterator(迭代器):定义访问和遍历元素的接口
- ConcreteIterator(具体迭代器):实现迭代器接口,跟踪遍历的当前位置
- Aggregate(聚合):定义创建相应迭代器对象的接口
- ConcreteAggregate(具体聚合):实现创建相应迭代器的接口,返回具体迭代器的实例
为什么需要迭代器模式?
问题场景
假设我们有一个社交应用,需要管理用户的好友列表。好友可能存储在数组、链表或数据库中,客户端代码需要遍历这些好友进行各种操作。
没有迭代器模式时,代码可能会是这样:
// 数组存储的好友
public class ArrayFriendList {
private String[] friends;
public String[] getFriends() {
return friends;
}
}
// 链表存储的好友
public class LinkedListFriendList {
private Node head;
public Node getHead() {
return head;
}
}
// 客户端代码需要了解不同集合的内部结构
public class Client {
public void processFriends(Object friendList) {
if (friendList instanceof ArrayFriendList) {
String[] friends = ((ArrayFriendList) friendList).getFriends();
for (int i = 0; i < friends.length; i++) {
System.out.println(friends[i]);
}
} else if (friendList instanceof LinkedListFriendList) {
Node current = ((LinkedListFriendList) friendList).getHead();
while (current != null) {
System.out.println(current.getData());
current = current.getNext();
}
}
// 每增加一种新的集合类型,就需要修改这里的代码
}
}
这种实现方式存在明显的问题:
- 客户端代码与具体集合实现紧密耦合
- 添加新的集合类型需要修改客户端代码
- 遍历逻辑分散在多个地方,难以维护
迭代器模式的实现
让我们用迭代器模式重构上述场景:
1. 定义迭代器接口
/**
* 迭代器接口
*/
public interface Iterator<T> {
boolean hasNext();
T next();
void remove();
}
2. 定义聚合接口
/**
* 聚合接口
*/
public interface Aggregate<T> {
Iterator<T> createIterator();
void add(T item);
int size();
}
3. 实现具体迭代器
/**
* 数组迭代器
*/
public class ArrayIterator<T> implements Iterator<T> {
private T[] array;
private int position = 0;
public ArrayIterator(T[] array) {
this.array = array;
}
@Override
public boolean hasNext() {
return position < array.length && array[position] != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array[position++];
}
@Override
public void remove() {
if (position <= 0) {
throw new IllegalStateException();
}
array[position - 1] = null;
// 实际应用中可能需要移动数组元素
}
}
/**
* 链表迭代器
*/
public class LinkedListIterator<T> implements Iterator<T> {
private Node<T> current;
public LinkedListIterator(Node<T> head) {
this.current = head;
}
@Override
public boolean hasNext() {
return current != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
T data = current.getData();
current = current.getNext();
return data;
}
@Override
public void remove() {
// 链表删除操作较为复杂,这里简化实现
throw new UnsupportedOperationException("Remove not supported");
}
}
4. 实现具体聚合类
/**
* 基于数组的好友列表
*/
public class ArrayFriendList implements Aggregate<String> {
private String[] friends;
private int size;
private static final int DEFAULT_CAPACITY = 10;
public ArrayFriendList() {
this.friends = new String[DEFAULT_CAPACITY];
this.size = 0;
}
@Override
public Iterator<String> createIterator() {
return new ArrayIterator<>(friends);
}
@Override
public void add(String friend) {
if (size >= friends.length) {
// 扩容逻辑
String[] newArray = new String[friends.length * 2];
System.arraycopy(friends, 0, newArray, 0, friends.length);
friends = newArray;
}
friends[size++] = friend;
}
@Override
public int size() {
return size;
}
}
/**
* 基于链表的好友列表
*/
public class LinkedListFriendList implements Aggregate<String> {
private Node<String> head;
private Node<String> tail;
private int size;
public LinkedListFriendList() {
this.head = null;
this.tail = null;
this.size = 0;
}
@Override
public Iterator<String> createIterator() {
return new LinkedListIterator<>(head);
}
@Override
public void add(String friend) {
Node<String> newNode = new Node<>(friend);
if (head == null) {
head = newNode;
tail = newNode;
} else {
tail.setNext(newNode);
tail = newNode;
}
size++;
}
@Override
public int size() {
return size;
}
}
/**
* 链表节点
*/
class Node<T> {
private T data;
private Node<T> next;
public Node(T data) {
this.data = data;
this.next = null;
}
public T getData() {
return data;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
}
5. 客户端代码
/**
* 客户端代码
*/
public class SocialApp {
public static void main(String[] args) {
// 创建不同的好友列表
Aggregate<String> arrayFriends = new ArrayFriendList();
Aggregate<String> linkedListFriends = new LinkedListFriendList();
// 添加好友
arrayFriends.add("Alice");
arrayFriends.add("Bob");
arrayFriends.add("Charlie");
linkedListFriends.add("David");
linkedListFriends.add("Eve");
linkedListFriends.add("Frank");
// 统一的方式遍历不同的集合
System.out.println("Array Friends:");
processFriends(arrayFriends);
System.out.println("\nLinked List Friends:");
processFriends(linkedListFriends);
}
public static void processFriends(Aggregate<String> friendList) {
Iterator<String> iterator = friendList.createIterator();
while (iterator.hasNext()) {
String friend = iterator.next();
System.out.println("Processing friend: " + friend);
// 对好友进行各种操作
}
}
}
迭代器模式的优势
1. 简化客户端代码
客户端不需要了解集合的内部结构,只需要通过统一的迭代器接口进行遍历。
2. 支持多种遍历方式
可以为同一个集合提供不同的迭代器,实现不同的遍历策略:
/**
* 反向迭代器
*/
public class ReverseArrayIterator<T> implements Iterator<T> {
private T[] array;
private int position;
public ReverseArrayIterator(T[] array, int size) {
this.array = array;
this.position = size - 1;
}
@Override
public boolean hasNext() {
return position >= 0 && array[position] != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return array[position--];
}
@Override
public void remove() {
throw new UnsupportedOperationException("Remove not supported in reverse iterator");
}
}
3. 开闭原则
增加新的集合类型不需要修改现有的遍历代码,符合开闭原则。
4. 并行遍历
可以在同一个集合上同时进行多个遍历操作:
public static void findCommonFriends(Aggregate<String> friends1, Aggregate<String> friends2) {
Iterator<String> iterator1 = friends1.createIterator();
while (iterator1.hasNext()) {
String friend1 = iterator1.next();
Iterator<String> iterator2 = friends2.createIterator();
while (iterator2.hasNext()) {
String friend2 = iterator2.next();
if (friend1.equals(friend2)) {
System.out.println("Common friend: " + friend1);
break;
}
}
}
}
实际应用场景
1. Java集合框架
Java的java.util.Iterator
和java.lang.Iterable
接口是迭代器模式的典型应用:
List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> iterator = list.iterator();
// 使用增强for循环(语法糖)
for (String item : list) {
System.out.println(item);
}
// 等价于
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println(item);
}
2. 数据库查询结果集
数据库驱动通常使用迭代器模式来遍历查询结果:
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
while (resultSet.next()) {
String username = resultSet.getString("username");
String email = resultSet.getString("email");
// 处理数据
}
3. 文件系统遍历
遍历目录树结构:
public class DirectoryIterator implements Iterator<File> {
private Queue<File> queue = new LinkedList<>();
public DirectoryIterator(File root) {
if (root.isDirectory()) {
queue.offer(root);
}
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
@Override
public File next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
File current = queue.poll();
if (current.isDirectory()) {
File[] children = current.listFiles();
if (children != null) {
for (File child : children) {
queue.offer(child);
}
}
}
return current;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
进阶应用:内部迭代器 vs 外部迭代器
外部迭代器
我们之前实现的都是外部迭代器,由客户端控制迭代过程:
// 客户端控制迭代
Iterator<String> iterator = collection.createIterator();
while (iterator.hasNext()) {
String item = iterator.next();
process(item);
}
内部迭代器
内部迭代器将迭代控制权交给迭代器本身,客户端提供回调函数:
/**
* 内部迭代器接口
*/
public interface InternalIterator<T> {
void forEach(Consumer<T> action);
}
/**
* 使用内部迭代器
*/
public class InternalArrayIterator<T> implements InternalIterator<T> {
private T[] array;
public InternalArrayIterator(T[] array) {
this.array = array;
}
@Override
public void forEach(Consumer<T> action) {
for (T item : array) {
if (item != null) {
action.accept(item);
}
}
}
}
// 客户端使用
InternalIterator<String> iterator = new InternalArrayIterator<>(friends);
iterator.forEach(friend -> {
System.out.println("Processing: " + friend);
// 其他处理逻辑
});
总结
迭代器模式通过将遍历行为抽象为独立的对象,实现了集合结构与遍历算法的分离。这种分离带来了诸多好处:
- 统一的访问接口:不同类型的集合可以使用相同的方式进行遍历
- 简化客户端代码:客户端不需要了解集合的内部实现
- 支持多种遍历方式:可以为同一集合提供不同的迭代器
- 符合开闭原则:新增集合类型不影响现有代码
在现代编程语言中,迭代器模式已经被广泛集成到语言特性中(如Java的foreach循环、C#的LINQ、Python的生成器等),成为处理集合数据的标准方式。掌握迭代器模式不仅有助于理解这些语言特性的底层原理,还能在需要自定义集合类型时设计出更加优雅的API。
虽然迭代器模式在大多数情况下已经被语言内置特性所替代,但理解其设计思想对于编写高质量、可维护的代码仍然具有重要意义。