当前位置: 首页 > news >正文

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

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

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

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

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

核心思想与 UML 类图

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

PlantUML Diagram

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

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

public interface Iterator {boolean hasNext();Object next();
}

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

public interface Aggregate {Iterator createIterator();
}

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

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];}@Overridepublic 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;}@Overridepublic boolean hasNext() {return index < aggregate.size();}@Overridepublic Object next() {return aggregate.getItem(index++);}}
}

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

// 链表节点类
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;}}@Overridepublic Iterator createIterator() {return new ListIterator(head);}// 链表迭代器类private class ListIterator implements Iterator {private ListNode current;public ListIterator(ListNode head) {this.current = head;}@Overridepublic boolean hasNext() {return current != null;}@Overridepublic Object next() {Object data = current.data;current = current.next;return data;}}
}

5. 客户端调用示例

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. 倒序遍历迭代器

public class ReverseArrayIterator implements Iterator {private ArrayAggregate aggregate;private int index;public ReverseArrayIterator(ArrayAggregate aggregate) {this.aggregate = aggregate;this.index = aggregate.size() - 1;}@Overridepublic boolean hasNext() {return index >= 0;}@Overridepublic 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. 并发安全迭代器(使用读写锁)

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();}}@Overridepublic 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;}@Overridepublic boolean hasNext() {lock.readLock().lock();try {return index < aggregate.size();} finally {lock.readLock().unlock();}}@Overridepublic Object next() {lock.readLock().lock();try {return aggregate.getItem(index++);} finally {lock.readLock().unlock();}}}
}

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

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

  • 核心接口java.util.Iteratorjava.util.ListIterator
  • 示例:遍历ArrayList
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

  • 用于处理大量数据查询,避免一次性加载全部数据到内存
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关键字简化迭代器实现
# 生成器函数
def fibonacci():a, b = 0, 1while True:yield aa, b = b, a + b# 使用生成器
for num in fibonacci():if num > 100:breakprint(num)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

http://www.xdnf.cn/news/9217.html

相关文章:

  • ctf.show—Web(1-10)详细通关教程
  • 2025年行业AI Agent选型专业指南
  • RT-Thread RTThread studio 初使用
  • 零基础玩转AI数学建模:从理论到实战
  • LINUX学习——守护进程的含义及编程实现
  • Function Calling的机制 (含示例)
  • Sqlite3交叉编译全过程
  • 2025妈妈杯数学建模B题完整分析论文
  • 游戏引擎学习第233天
  • 【go】什么是Go语言中的GC,作用是什么?调优,sync.Pool优化,逃逸分析演示
  • 深度学习神经网络全连接笔记day1
  • 2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(四级)真题
  • python flask 项目部署
  • 源码分析之Leaflet中Point
  • CSS 美化页面(五)
  • TikTok流量变现全攻略:免费与付费玩法解析
  • 【项目管理】第19章 配置与变更管理-- 知识点整理
  • 嵌入式ARM RISCV toolchain工具 梳理arm-none-eabi-gcc
  • 第八篇:系统分析师第三遍——3、4章
  • index: 自动化浏览器智能体
  • 【 图像梯度处理,图像边缘检测】图像处理(OpenCv)-part6
  • HarmonyOS 基础语法概述 UI范式
  • 双击热备方案及不同方案的需求、方案对比
  • hive的基础配置优化与数仓流程
  • GitHub Copilot在产品/安全团队中的应用实践:处理Markdown、自动化报告与电子表格、使用CLI命令等
  • leetcode0145. 二叉树的后序遍历-easy
  • AutoSAR从概念到实践系列之MCAL篇(一)——MCAL架构及其模块详解
  • 手撕数据结构算法OJ——栈和队列
  • eNSP无法启动AR报错码40,而且按照eNSP帮助手册排查都没用,我的处理方法【自己存档版】
  • 2N60-ASEMI功业控制与自动化专用2N60