迭代器模式:告别混乱遍历,统一集合访问之道

2025/10/15 Design Patterns 共 7856 字,约 23 分钟

迭代器模式:统一遍历集合的方式

在软件开发中,我们经常需要处理各种集合对象,如数组、列表、树、图等。不同的集合数据结构有着不同的内部表示和遍历方式,这给客户端代码带来了复杂性。迭代器模式应运而生,它提供了一种统一的方法来顺序访问集合对象中的元素,而不需要暴露其底层实现。

什么是迭代器模式?

迭代器模式(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. 客户端代码与具体集合实现紧密耦合
  2. 添加新的集合类型需要修改客户端代码
  3. 遍历逻辑分散在多个地方,难以维护

迭代器模式的实现

让我们用迭代器模式重构上述场景:

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.Iteratorjava.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);
    // 其他处理逻辑
});

总结

迭代器模式通过将遍历行为抽象为独立的对象,实现了集合结构与遍历算法的分离。这种分离带来了诸多好处:

  1. 统一的访问接口:不同类型的集合可以使用相同的方式进行遍历
  2. 简化客户端代码:客户端不需要了解集合的内部实现
  3. 支持多种遍历方式:可以为同一集合提供不同的迭代器
  4. 符合开闭原则:新增集合类型不影响现有代码

在现代编程语言中,迭代器模式已经被广泛集成到语言特性中(如Java的foreach循环、C#的LINQ、Python的生成器等),成为处理集合数据的标准方式。掌握迭代器模式不仅有助于理解这些语言特性的底层原理,还能在需要自定义集合类型时设计出更加优雅的API。

虽然迭代器模式在大多数情况下已经被语言内置特性所替代,但理解其设计思想对于编写高质量、可维护的代码仍然具有重要意义。

文档信息

Search

    Table of Contents