迭代器模式:统一不同数据结构的遍历方式

迭代器模式:统一不同数据结构的遍历方式

一、模式核心:分离数据遍历与数据表示

在开发中,我们经常需要遍历不同的数据结构,如数组、链表、树等。若在客户端代码中直接编写遍历逻辑,不仅会导致代码冗余,而且当数据结构发生变化时,遍历逻辑也需要随之修改。迭代器模式(Iterator Pattern 通过将遍历逻辑封装成独立的迭代器对象,实现数据结构与遍历算法的解耦,核心解决:

  • 统一遍历接口 :为不同数据结构提供一致的遍历方式,如hasNext()next()
  • 隐藏数据结构细节:客户端无需了解数据存储的具体结构(如链表的节点操作),仅通过迭代器操作数据。
  • 支持复杂遍历:方便实现倒序遍历、跳跃遍历等特殊遍历需求。

核心思想与 UML 类图

迭代器模式主要包含迭代器接口、具体迭代器、聚合接口和具体聚合四个角色:

二、核心实现:自定义数组与链表的统一遍历

1. 定义迭代器接口(规范遍历操作)

java 复制代码
public interface Iterator {
    boolean hasNext();
    Object next();
}

2. 定义聚合接口(提供创建迭代器的方法)

java 复制代码
public interface Aggregate {
    Iterator createIterator();
}

3. 实现具体聚合类(以数组为例)

java 复制代码
public class ArrayAggregate implements Aggregate {
    private Object[] items;
    private int size;

    public ArrayAggregate(int capacity) {
        items = new Object[capacity];
    }

    public void addItem(Object item) {
        items[size++] = item;
    }

    public int size() {
        return size;
    }

    public Object getItem(int index) {
        return items[index];
    }

    @Override
    public Iterator createIterator() {
        return new ArrayIterator(this);
    }

    // 具体迭代器类(内部类)
    private class ArrayIterator implements Iterator {
        private ArrayAggregate aggregate;
        private int index = 0;

        public ArrayIterator(ArrayAggregate aggregate) {
            this.aggregate = aggregate;
        }

        @Override
        public boolean hasNext() {
            return index < aggregate.size();
        }

        @Override
        public Object next() {
            return aggregate.getItem(index++);
        }
    }
}

4. 实现链表聚合类及对应迭代器

java 复制代码
// 链表节点类
class ListNode {
    Object data;
    ListNode next;

    public ListNode(Object data) {
        this.data = data;
    }
}

// 链表聚合类
public class ListAggregate implements Aggregate {
    private ListNode head;

    public void addItem(Object item) {
        ListNode newNode = new ListNode(item);
        if (head == null) {
            head = newNode;
        } else {
            ListNode current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    @Override
    public Iterator createIterator() {
        return new ListIterator(head);
    }

    // 链表迭代器类
    private class ListIterator implements Iterator {
        private ListNode current;

        public ListIterator(ListNode head) {
            this.current = head;
        }

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public Object next() {
            Object data = current.data;
            current = current.next;
            return data;
        }
    }
}

5. 客户端调用示例

java 复制代码
public class ClientDemo {
    public static void main(String[] args) {
        // 使用数组聚合类
        ArrayAggregate arrayAggregate = new ArrayAggregate(3);
        arrayAggregate.addItem("Apple");
        arrayAggregate.addItem("Banana");
        arrayAggregate.addItem("Cherry");
        Iterator arrayIterator = arrayAggregate.createIterator();
        while (arrayIterator.hasNext()) {
            System.out.println(arrayIterator.next());
        }

        // 使用链表聚合类
        ListAggregate listAggregate = new ListAggregate();
        listAggregate.addItem("Dog");
        listAggregate.addItem("Elephant");
        listAggregate.addItem("Fox");
        Iterator listIterator = listAggregate.createIterator();
        while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
        }
    }
}

三、进阶:实现倒序遍历与并发安全迭代器

1. 倒序遍历迭代器

java 复制代码
public class ReverseArrayIterator implements Iterator {
    private ArrayAggregate aggregate;
    private int index;

    public ReverseArrayIterator(ArrayAggregate aggregate) {
        this.aggregate = aggregate;
        this.index = aggregate.size() - 1;
    }

    @Override
    public boolean hasNext() {
        return index >= 0;
    }

    @Override
    public Object next() {
        return aggregate.getItem(index--);
    }
}

// 客户端调用倒序遍历
ArrayAggregate arrayAggregate = new ArrayAggregate(3);
// 添加元素...
Iterator reverseIterator = new ReverseArrayIterator(arrayAggregate);
while (reverseIterator.hasNext()) {
    System.out.println(reverseIterator.next());
}

2. 并发安全迭代器(使用读写锁)

java 复制代码
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ThreadSafeArrayAggregate implements Aggregate {
    private Object[] items;
    private int size;
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public ThreadSafeArrayAggregate(int capacity) {
        items = new Object[capacity];
    }

    public void addItem(Object item) {
        lock.writeLock().lock();
        try {
            items[size++] = item;
        } finally {
            lock.writeLock().unlock();
        }
    }

    public int size() {
        lock.readLock().lock();
        try {
            return size;
        } finally {
            lock.readLock().unlock();
        }
    }

    public Object getItem(int index) {
        lock.readLock().lock();
        try {
            return items[index];
        } finally {
            lock.readLock().unlock();
        }
    }

    @Override
    public Iterator createIterator() {
        return new ThreadSafeArrayIterator(this);
    }

    private class ThreadSafeArrayIterator implements Iterator {
        private ThreadSafeArrayAggregate aggregate;
        private int index = 0;

        public ThreadSafeArrayIterator(ThreadSafeArrayAggregate aggregate) {
            this.aggregate = aggregate;
        }

        @Override
        public boolean hasNext() {
            lock.readLock().lock();
            try {
                return index < aggregate.size();
            } finally {
                lock.readLock().unlock();
            }
        }

        @Override
        public Object next() {
            lock.readLock().lock();
            try {
                return aggregate.getItem(index++);
            } finally {
                lock.readLock().unlock();
            }
        }
    }
}

四、框架与源码中的迭代器实践

1. Java 集合框架(java.util包)

  • 核心接口java.util.Iteratorjava.util.ListIterator
  • 示例 :遍历ArrayList
java 复制代码
import java.util.ArrayList;
import java.util.Iterator;

public class JavaIteratorExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

2. Hibernate 的迭代器(ScrollableResults

  • 用于处理大量数据查询,避免一次性加载全部数据到内存
java 复制代码
Session session = sessionFactory.openSession();
Query query = session.createQuery("from User");
ScrollableResults results = query.scroll();
while (results.next()) {
    User user = (User) results.get(0);
    // 处理用户数据
}
results.close();

3. Python 中的迭代器与生成器

  • 迭代器协议 :通过__iter__()__next__()方法实现
  • 生成器 :使用yield关键字简化迭代器实现
python 复制代码
# 生成器函数
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 使用生成器
for num in fibonacci():
    if num > 100:
        break
    print(num)

五、避坑指南:正确使用迭代器模式的 3 个要点

1. 避免在迭代过程中修改聚合对象

  • ❌ 反模式:在迭代器遍历过程中删除聚合元素(可能导致ConcurrentModificationException
  • ✅ 最佳实践:使用remove()方法(若迭代器支持),或先记录待删除元素,遍历结束后再操作。

2. 处理空聚合的边界情况

  • 确保hasNext()在空聚合中返回falsenext()在空聚合或遍历结束后抛出NoSuchElementException

3. 迭代器的生命周期管理

  • 避免迭代器被长时间持有,导致资源无法释放(如数据库游标未关闭)。
  • 对于一次性遍历需求,可使用匿名内部类或局部内部类简化代码。

4. 反模式:过度封装简单遍历

  • 对于简单的数组或集合遍历,直接使用for-each循环可能更简洁,无需引入迭代器模式。

六、总结:何时该用迭代器模式?

适用场景 核心特征 典型案例
遍历多种数据结构 数据存储结构复杂(如树、图),需统一遍历方式 文件系统目录遍历、数据库查询结果遍历
分离数据结构与遍历逻辑 避免客户端耦合具体数据结构实现细节 集合框架、ORM 框架
支持复杂遍历需求 需要实现倒序遍历、跳跃遍历、并发遍历等 大数据处理、多线程迭代

迭代器模式通过 "封装遍历 + 解耦结构" 的设计,使数据的访问与存储方式分离,提升了代码的可维护性和扩展性。下一篇我们将深入探讨装饰模式,解析如何在不修改原有类的基础上动态添加功能,敬请期待!

扩展思考:迭代器模式 vs 枚举(Enumeration)

模式 功能特性 线程安全 可修改性 典型应用
迭代器模式 支持删除、双向遍历、自定义遍历 需手动实现 支持 集合框架、复杂数据结构遍历
枚举 仅支持单向遍历,功能较简单 部分支持 不支持 早期 Java 集合遍历

理解这些差异,有助于在不同场景下选择合适的遍历方案。

相关推荐
算法练习生11 分钟前
数据结构学习笔记 :排序算法详解与C语言实现
数据结构·学习·排序算法
SuperCandyXu3 小时前
leetcode0113. 路径总和 II - medium
数据结构·c++·算法·leetcode
硬匠的博客3 小时前
C++继承与派生
数据结构·算法
purrrew3 小时前
【数据结构_11】二叉树(3)
java·数据结构
rigidwill6663 小时前
LeetCode hot 100—单词搜索
数据结构·c++·算法·leetcode·职场和发展
描绘一抹色3 小时前
力扣-hot100(无重复字符的最长子串)
数据结构·算法·leetcode
【0931】3 小时前
反转一个字符串
数据结构·算法
Achou.Wang4 小时前
数据库基础-B+树
数据结构·数据库·b树
厚衣服_34 小时前
Python语法系列博客 · 第7期[特殊字符] 列表推导式与字典推导式:更优雅地处理数据结构
java·数据结构·python