首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

迭代器模式:统一数据遍历方式的设计模式

  • 25-04-24 18:47
  • 4729
  • 10350
juejin.cn

迭代器模式:统一数据遍历方式的设计模式

一、模式核心:将数据遍历逻辑与数据结构解耦

在软件开发中,不同的数据结构(如数组、链表、集合)有不同的遍历方式。如果客户端直接依赖这些数据结构的内部实现来遍历元素,会导致代码耦合度高且难以维护。

迭代器模式(Iterator Pattern) 提供了一种统一的方式来遍历不同的数据结构,而无需暴露数据结构的内部表示。其核心解决:

  • 解耦遍历逻辑:将遍历逻辑从数据结构中分离,客户端通过迭代器统一操作。
  • 支持多种遍历方式:可以为同一数据结构提供不同的遍历策略(如正向遍历、反向遍历)。
  • 简化客户端代码:客户端无需关心数据结构的具体类型,只需通过迭代器接口遍历元素。

核心思想与 UML 类图

迭代器模式包含以下角色:

  1. 抽象迭代器(Iterator):定义遍历元素的接口(如 hasNext()、next())。
  2. 具体迭代器(Concrete Iterator):实现抽象迭代器接口,负责具体的数据遍历。
  3. 抽象聚合(Aggregate):定义创建迭代器的接口(如 createIterator())。
  4. 具体聚合(Concrete Aggregate):实现抽象聚合接口,返回具体迭代器。

PlantUML Diagram

二、核心实现:数组集合的迭代器

1. 定义抽象迭代器接口

java
代码解读
复制代码
public interface Iterator { boolean hasNext(); // 是否有下一个元素 Object next(); // 获取下一个元素 }

2. 定义抽象聚合接口

java
代码解读
复制代码
public interface Aggregate { Iterator createIterator(); // 创建迭代器 }

3. 实现具体聚合类(数组集合)

java
代码解读
复制代码
public class ConcreteAggregate implements Aggregate { private Object[] items; private int size; public ConcreteAggregate(int capacity) { items = new Object[capacity]; size = 0; } public void add(Object item) { if (size < items.length) { items[size++] = item; } } @Override public Iterator createIterator() { return new ConcreteIterator(this); // 返回具体迭代器 } // 获取集合长度(供迭代器使用) public int getSize() { return size; } // 获取指定索引的元素(供迭代器使用) public Object getItem(int index) { return items[index]; } }

4. 实现具体迭代器类

java
代码解读
复制代码
public class ConcreteIterator implements Iterator { private ConcreteAggregate aggregate; private int index; // 当前遍历位置 public ConcreteIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; index = 0; } @Override public boolean hasNext() { return index < aggregate.getSize(); // 未遍历到末尾 } @Override public Object next() { if (hasNext()) { return aggregate.getItem(index++); // 返回当前元素并后移索引 } return null; } }

5. 客户端使用迭代器

java
代码解读
复制代码
public class ClientDemo { public static void main(String[] args) { // 创建聚合对象并添加元素 ConcreteAggregate aggregate = new ConcreteAggregate(3); aggregate.add("Apple"); aggregate.add("Banana"); aggregate.add("Cherry"); // 获取迭代器并遍历元素 Iterator iterator = aggregate.createIterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }

输出结果:

plaintext
代码解读
复制代码
Apple Banana Cherry

三、进阶:支持反向遍历的迭代器

通过扩展具体迭代器,可以为同一聚合提供不同的遍历策略(如反向遍历)。

1. 新增反向迭代器类

java
代码解读
复制代码
public class ReverseIterator implements Iterator { private ConcreteAggregate aggregate; private int index; // 当前遍历位置(从末尾开始) public ReverseIterator(ConcreteAggregate aggregate) { this.aggregate = aggregate; index = aggregate.getSize() - 1; // 初始位置为最后一个元素 } @Override public boolean hasNext() { return index >= 0; // 未遍历到开头 } @Override public Object next() { if (hasNext()) { return aggregate.getItem(index--); // 返回当前元素并前移索引 } return null; } }

2. 修改聚合类以支持多种迭代器

java
代码解读
复制代码
public class ConcreteAggregate { // ... 原有代码 ... // 新增创建反向迭代器的方法 public Iterator createReverseIterator() { return new ReverseIterator(this); } }

3. 客户端使用反向迭代器

java
代码解读
复制代码
public class ClientDemo { public static void main(String[] args) { // ... 创建聚合对象 ... // 反向遍历 Iterator reverseIterator = aggregate.createReverseIterator(); while (reverseIterator.hasNext()) { System.out.println(reverseIterator.next()); } } }

输出结果:

plaintext
代码解读
复制代码
Cherry Banana Apple

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

1. Java 集合框架(Iterator 接口)

Java 的 java.util.Iterator 是迭代器模式的标准实现,所有集合类(如 ArrayList、HashSet)均实现了 Iterable 接口(包含 iterator() 方法)。

java
代码解读
复制代码
List list = new ArrayList<>(); list.add("A"); list.add("B"); Iterator it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); }

2. MyBatis 结果集遍历

MyBatis 在处理查询结果时,通过 ResultHandler 接口实现类似迭代器的功能,将结果集逐行处理,避免一次性加载大量数据到内存。

java
代码解读
复制代码
sqlSession.select("selectUserList", new ResultHandler() { @Override public void handleResult(ResultContext context) { User user = context.getResultObject(); processUser(user); // 逐行处理结果 } });

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

1. 确保迭代器的独立性

每个迭代器应独立维护遍历状态,避免多个迭代器共享状态导致数据不一致。

2. 处理并发修改异常

在迭代过程中修改聚合对象(如新增 / 删除元素)可能导致 ConcurrentModificationException,需通过 fail-fast 机制或复制集合数据处理。

3. 避免过度设计

对于简单的数据结构(如数组),直接使用索引遍历可能更高效,无需强行引入迭代器模式。

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

适用场景核心特征典型案例
数据结构复杂数据结构内部实现复杂,需隐藏遍历细节链表、树状结构遍历
多遍历策略需要为同一数据结构提供多种遍历方式正向 / 反向遍历、深度 / 广度优先
解耦客户端与数据结构客户端不依赖数据结构的具体实现集合框架、ORM 结果集处理

迭代器模式通过分离数据遍历逻辑,提升了代码的可维护性和扩展性。下一篇我们将探讨观察者模式,解析如何实现对象间的消息订阅与发布,敬请期待!

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

类型功能差异线程安全遍历控制
迭代器支持元素删除(remove())非线程安全主动控制遍历
枚举(旧版)仅支持遍历,不支持删除非线程安全被动遍历

在 Java 中,迭代器已全面替代枚举,成为集合遍历的标准方式。

注:本文转载自juejin.cn的AronTing的文章"https://juejin.cn/post/7496335321802932250"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top