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

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

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

在开发中,我们经常需要遍历不同的数据结构,如数组、链表、树等。若在客户端代码中直接编写遍历逻辑,不仅会导致代码冗余,而且当数据结构发生变化时,遍历逻辑也需要随之修改。迭代器模式(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.mzph.cn/pingmian/77457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle 如何停止正在运行的 Job

Oracle 如何停止正在运行的 Job 先了解是dbms_job 还是 dbms_scheduler&#xff0c;再确定操作命令。 一 使用 DBMS_JOB 包停止作业&#xff08;适用于旧版 Job&#xff09; 1.1 查看正在运行的 Job SELECT job, what, this_date, this_sec, failures, broken FROM user_j…

真实波幅策略思路

该策略是一种基于ATR&#xff08;Average True Range&#xff09;指标的交易策略&#xff0c;主要用于期货市场中的日内交易。策略的核心思想是利用ATR指标来识别市场的波动范围&#xff0c;并结合均线过滤来确定买入和卖出的时机。 交易逻辑思维 1. 数据准备与初始化 - 集合竞…

Web3技术如何提升用户数据保护

在这个信息爆炸的时代&#xff0c;用户数据保护已成为全球关注的焦点。Web3 技术&#xff0c;作为下一代互联网的代表&#xff0c;以其去中心化、安全性和用户主权等特点&#xff0c;为用户数据保护提供了新的解决方案。本文将探讨 Web3 技术如何提升用户数据保护。 去中心化存…

银河麒麟系统 达梦8 安装 dlask 框架后端环境

适配的一套环境为 dmPython2.5.8 dmSQLAlchemy1.4.39 Flask2.0.3 Flask-Cors3.0.10 Flask-SQLAlchemy2.5.1 SQLAlchemy1.4.54 Werkzeug2.2.2其中 # sqlalchemy-dm1.4.39 通过dmdbms目录内文件进行源码安装 (MindSpore) [ma-user python]$pwd /home/syl/dmdbms/drivers/python…

利用 i2c 快速从 Interface 生成 Class

利用 i2c 快速从 Interface 生成 Class&#xff08;支持 TS & ArkTS&#xff09; 在日常 TypeScript 或 ArkTS 开发中&#xff0c;需要根据 interface 定义手动实现对应的 class&#xff0c;这既重复又容易出错。分享一个命令行工具 —— interface2class&#xff0c;简称…

015-C语言字符函数和字符串函数

C语言字符函数和字符串函数 文章目录 C语言字符函数和字符串函数1. 字符分类函数2. 字符转换函数3. strlen4. strcpy5. strcat6. strcmp7. strncpy8. strncat9. strncmp10. strstr11. strtok12. strerror 1. 字符分类函数 C语言中有一系列函数是专门做字符分类的&#xff0c;也…

CGAL边折叠edge_collapse的问题

使用edge_collapse对一个模型简化&#xff0c;之后回收垃圾&#xff0c;collect_garbage 处理之前的顶点和三角形数量&#xff1a; number_of_vertices: 955730 number_of_faces: 1903410 num_vertices: 955730 num_faces: 1903410 处理之后的顶点和三角形数量&#xff1a;…

用c语言实现——顺序队列支持用户输入交互、入队、出队、查找、遍历、计算队列长度等功能。确定判断判满的方法为:牺牲一个存储单元方式

一、知识介绍 1.基本原理 在顺序队列中&#xff0c;我们使用一个固定大小的数组来存储队列中的元素&#xff0c;并使用两个指针&#xff08;front 和 rear&#xff09;来分别表示队头和队尾的位置。 队列为空的条件&#xff1a;front rear 队列满的条件&#xff1a;rear 1…

JVM 系列:JVM 内存结构深度解析

你点赞了吗&#xff1f;你关注了吗&#xff1f;每天分享干货好文。 高并发解决方案与架构设计。 海量数据存储和性能优化。 通用框架/组件设计与封装。 如何设计合适的技术架构&#xff1f; 如何成功转型架构设计与技术管理&#xff1f; 在竞争激烈的大环境下&#xff0c…

手机上的APN是什么,该怎么设置

网上说改个APN就可以让网速快几倍&#xff0c;那到底APN是个什么东西&#xff0c;真的能让网速快几倍吗&#xff1f; APN的作用 网络连接基础&#xff1a;APN&#xff08;接入点名称&#xff09;是手机连接移动网络的“桥梁”&#xff0c;负责识别运营商网络类型&#xff08;…

微服务治理与可观测性

服务注册与发现 核心功能 服务实例动态变化&#xff1a;实例可能因扩缩容、故障或迁移导致IP变动。服务依赖解耦&#xff1a;调用方无需硬编码服务地址&#xff0c;降低耦合度。负载均衡&#xff1a;自动选择健康实例&#xff0c;提升系统可用性。 核心组件 服务注册中心&am…

嵌入式linux系统中内存管理的方法与实现

第一:linux内核管理详解图形 第二:Linux内存管理详细分析 深入剖析Linux内核内存管理 作为嵌入式系统开发者,理解Linux内核的内存管理对于开发高效、稳定的系统至关重要。在这篇文章中,我们将详细解析Linux内核如何划分物理内存和虚拟内存,页表、MMU(内存管理单元)与TL…

【dataframe显示不全问题】打开一个行列超多的excel转成df之后行列显示不全

出现问题如下图&#xff1a; 解决方案&#xff5e; display.width解决列显示不全 pd.set_option(display.max_columns,1000) pd.set_option(display.width, 1000) pd.set_option(display.max_colwidth,1000) pd.set_option(display.max_rows,1000)

Linux——Shell编程之正则表达式与文本处理器(笔记)

目录 基础正则表达式 1:基础正则表达式示例 &#xff08;4&#xff09;查找任意一个字符“.”与重新字符“*” &#xff08;5&#xff09;查找连续字符范围“{ }” 文本处理器 一、sed工具 二、awk工具 &#xff08;1&#xff09;按行输出文本 &#xff08;2&#xff0…

OpenHarmony系统-源码下载,环境搭建,编译,烧录,调试

获取源码 以OpenHarmony5.0.3为例 repo init -u https://gitee.com/openharmony/manifest -b OpenHarmony-5.0.3-Release --no-repo-verify repo sync -c repo forall -c git lfs pull搭建环境 安装必要的工具和命令 apt-get install -y apt-utils binutils bison flex bc …

Vue3 本地打包启动白屏解决思路!! !

“为什么我访问 http://127.0.0.1:5501/index.html 白屏&#xff0c;删了 index.html 再访问 / 就又活过来了&#xff1f;” —— 你的项目与 SPA 路由的“宫斗大戏” 一、问题复现 场景 本地通过 VSCode Live Server&#xff08;或其他静态服务器&#xff09;启动了打包后的 V…

数字人(2):数字人技术全景透视(2025演进版)

随着人工智能技术的迅猛发展,数字人技术发展也是一日千里。站在当下,着眼未来,我们一起在回眸透视过去的基础上,一起共同眺望数字人技术的未来。 一、数字人技术体系重构 我们可以用三维定义对数字人技术进行框架重构 维度 技术内涵 典型特征 物理层 人体数字化建模技术 …

小刚说C语言刷题——1035 判断成绩等级

1.题目描述 输入某学生成绩&#xff0c;如果 86分以上(包括 86分&#xff09;则输出 VERY GOOD &#xff0c;如果在 60到 85之间的则输出 GOOD (包括 60和 85)&#xff0c;小于 60 的则输出 BAD。 输入 输入只有一行&#xff0c;包括 1个整数。 输出 输出只有一行&#xf…

React-在使用map循环数组渲染列表时须指定唯一且稳定值的key

在渲染列表的时候&#xff0c;我们须给组件或者元素分配一个唯一值的key, key是一个特殊的属性&#xff0c;不会最终加在元素上面&#xff0c;也无法通过props.key来获取&#xff0c;仅在react内部使用。react中的key本质是服务于diff算法, 它的默认值是null, 在diff算法过程中…

Zookeeper的通知机制是什么?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper的通知机制是什么&#xff1f;】面试题。希望对大家有帮助&#xff1b; Zookeeper的通知机制是什么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper 的通知机制是其核心特性之一&#xf…