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

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

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

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

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

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

核心思想与 UML 类图

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

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

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

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 是迭代器模式的标准实现,所有集合类(如 ArrayListHashSet)均实现了 Iterable 接口(包含 iterator() 方法)。

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

2. MyBatis 结果集遍历

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

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

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

1. 确保迭代器的独立性

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

2. 处理并发修改异常

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

3. 避免过度设计

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

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

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

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

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

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

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

相关推荐
一只叫煤球的猫2 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9652 小时前
tcp/ip 中的多路复用
后端
bobz9652 小时前
tls ingress 简单记录
后端
皮皮林5514 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友4 小时前
什么是OpenSSL
后端·安全·程序员
bobz9654 小时前
mcp 直接操作浏览器
后端
前端小张同学6 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook6 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康7 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在7 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net