Java设计模式-迭代器模式

发布于:2025-08-20 ⋅ 阅读:(22) ⋅ 点赞:(0)

Java设计模式-迭代器模式

模式概述

迭代器模式简介

核心思想:将集合对象的遍历逻辑与集合本身的实现解耦,通过定义一个统一的迭代器接口,封装对集合元素的访问方式,使得客户端可以通过相同的方式遍历不同类型的集合,无需关心集合的内部结构。

模式类型:行为型设计模式(关注对象间的交互与职责分配)。

作用

  • ​解耦遍历逻辑与集合实现​​:集合的内部结构(如数组、链表、树)变化时,只需修改具体迭代器,客户端遍历代码无需调整;
  • 支持多态遍历:不同集合(如ListSet)可通过同一迭代器接口实现遍历,客户端代码统一;
  • 简化复杂集合遍历:对于嵌套集合(如树形结构)或需要自定义遍历规则(如过滤、排序)的场景,迭代器可封装复杂逻辑。

典型应用场景

  • 集合框架遍历(如Java Collection/List/SetIterator);
  • 数据库查询结果集遍历(如JDBC ResultSet);
  • 文件系统目录遍历(如遍历文件夹下的所有文件);
  • 自定义复杂数据结构遍历(如图结构、树结构的深度优先/广度优先遍历)。

我认为:迭代器模式是“集合的万能钥匙”,用统一接口打开不同集合的遍历之门,让客户端优雅地“按顺序访问”而不必操心“门后结构”。

课程目标

  • 理解迭代器模式的核心思想和经典应用场景
  • 识别应用场景,使用迭代器模式解决功能要求
  • 了解迭代器模式的优缺点

核心组件

角色-职责表

角色 职责 示例类名
抽象迭代器(Iterator) 定义遍历集合元素的通用接口(如hasNext()next()remove() Iterator(Java内置接口)
具体迭代器(Concrete Iterator) 实现抽象迭代器接口,持有集合引用并记录当前遍历位置,负责具体遍历逻辑 ListIterator(列表迭代器)
抽象容器(Aggregate) 定义创建迭代器的方法(如iterator()),声明集合的基础操作 Collection(Java集合接口)
具体容器(Concrete Aggregate) 实现抽象容器的创建迭代器方法,返回对应具体迭代器实例 ArrayList(数组列表)

类图

下面是一个简化的类图表示,展示了迭代器模式中的主要角色及其交互方式:

扩展
创建
创建
实现
实现
实现
实现
实现
«interface»
Iterable
+iteractor()
«interface»
Iterator
+hasNext()
+next()
+remove()
«interface»
StudentIterator
+hasPrevious()
+previous()
GradeBook
-students: List
+addStudent(name: String)
+iterator()
+reverseIterator()
ForwardStudentIterator
-students: List
-cursor: int
+hasNext()
+next()
+hasPrevious()
+previous()
ReverseStudentIterator
-students: List
-cursor: int
+hasNext()
+next()
+hasPrevious()
+previous()

传统实现 VS 迭代器模式

案例需求

案例背景:实现一个支持多种遍历方式的“学生成绩册”系统,成绩册包含学生姓名列表,需要支持正向遍历(从第一个到最后一个)和反向遍历(从最后一个到第一个)。

传统实现(痛点版)

代码实现

// 传统成绩册(未使用迭代器)
class GradeBook {
    private List<String> students = new ArrayList<>();

    public void addStudent(String name) {
        students.add(name);
    }

    // 正向遍历(硬编码)
    public void traverseForward() {
        for (int i = 0; i < students.size(); i++) {
            System.out.print(students.get(i) + " ");
        }
        System.out.println();
    }

    // 反向遍历(硬编码)
    public void traverseBackward() {
        for (int i = students.size() - 1; i >= 0; i--) {
            System.out.print(students.get(i) + " ");
        }
        System.out.println();
    }
}

// 客户端使用
public class TraditionalDemo {
    public static void main(String[] args) {
        GradeBook book = new GradeBook();
        book.addStudent("张三");
        book.addStudent("李四");
        book.addStudent("王五");

        System.out.println("正向遍历:");
        book.traverseForward(); // 输出:张三 李四 王五 

        System.out.println("反向遍历:");
        book.traverseBackward(); // 输出:王五 李四 张三 
    }
}

痛点总结

  • 紧耦合:每增加一种遍历方式(如按性别过滤遍历),需修改GradeBook类并新增遍历方法,违反“开闭原则”;
  • 遍历逻辑分散:遍历代码嵌入集合类内部,客户端需了解不同遍历方法的差异;
  • 扩展性差:若成绩册的底层存储从List改为Set(如HashSet),正向/反向遍历方法可能失效(Set无索引)。

迭代器模式 实现(优雅版)

代码实现

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

// 抽象迭代器:定义遍历接口
interface StudentIterator extends Iterator<String> {
    // 可选:扩展反向遍历方法(非必须,视需求)
    boolean hasPrevious();
    String previous();
}

// 具体容器:成绩册(持有学生列表)
class GradeBook implements Iterable<String> {
    private List<String> students = new ArrayList<>();

    public void addStudent(String name) {
        students.add(name);
    }

    // 实现Iterable接口,返回具体迭代器
    @Override
    public Iterator<String> iterator() {
        return new ForwardStudentIterator(students);
    }

    // 可选:提供反向迭代器工厂方法
    public StudentIterator reverseIterator() {
        return new ReverseStudentIterator(students);
    }
}

// 具体迭代器:正向遍历
class ForwardStudentIterator implements StudentIterator {
    private final List<String> students;
    private int cursor = 0; // 当前遍历位置

    public ForwardStudentIterator(List<String> students) {
        this.students = students;
    }

    @Override
    public boolean hasNext() {
        return cursor < students.size();
    }

    @Override
    public String next() {
        if (!hasNext()) throw new IllegalStateException("无下一个元素");
        return students.get(cursor++);
    }

    @Override
    public boolean hasPrevious() {
        return cursor > 0;
    }

    @Override
    public String previous() {
        if (!hasPrevious()) throw new IllegalStateException("无上一个元素");
        return students.get(--cursor);
    }
}

// 具体迭代器:反向遍历
class ReverseStudentIterator implements StudentIterator {
    private final List<String> students;
    private int cursor; // 当前遍历位置(初始化为最后一个元素)

    public ReverseStudentIterator(List<String> students) {
        this.students = students;
        this.cursor = students.size() - 1;
    }

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

    @Override
    public String next() {
        if (!hasNext()) throw new IllegalStateException("无下一个元素");
        return students.get(cursor--);
    }

    @Override
    public boolean hasPrevious() {
        return cursor < students.size() - 1;
    }

    @Override
    public String previous() {
        if (!hasPrevious()) throw new IllegalStateException("无上一个元素");
        return students.get(++cursor);
    }
}

// 客户端使用
public class IteratorDemo {
    public static void main(String[] args) {
        GradeBook book = new GradeBook();
        book.addStudent("张三");
        book.addStudent("李四");
        book.addStudent("王五");

        System.out.println("正向遍历(默认迭代器):");
        Iterator<String> forwardIterator = book.iterator();
        while (forwardIterator.hasNext()) {
            System.out.print(forwardIterator.next() + " "); // 输出:张三 李四 王五 
        }

        System.out.println("
反向遍历(自定义迭代器):");
        StudentIterator reverseIterator = book.reverseIterator();
        while (reverseIterator.hasNext()) {
            System.out.print(reverseIterator.next() + " "); // 输出:王五 李四 张三 
        }

        // 扩展:新增“按奇偶位置过滤遍历”只需新增一个具体迭代器,无需修改GradeBook
    }
}

优势

  • ​解耦遍历逻辑​​:遍历方式(正向、反向、过滤等)由具体迭代器实现,成绩册(GradeBook)无需关心,符合“单一职责原则”;
  • 扩展性强:新增遍历方式只需添加新的迭代器类,无需修改现有代码,符合“开闭原则”;
  • 统一接口:客户端通过Iterator接口遍历,无需了解集合底层是List还是Set,提高代码通用性。

局限

  • 额外复杂度:简单遍历场景(如仅需正向遍历)下,迭代器模式会增加类和接口数量,可能“过度设计”;
  • 学习成本:客户端需熟悉迭代器接口(如hasNext()next()),但Java等语言已内置Iterator,降低了学习门槛。

模式变体

  • ​外部迭代器 vs 内部迭代器​​:
    • 外部迭代器:客户端显式控制遍历(如调用next()),灵活但需手动管理状态(如Java的Iterator);
    • 内部迭代器:迭代器内部控制遍历(如Java 8的forEach()或Stream API),客户端只需定义操作逻辑(如student -> System.out.print(student + " "))。
  • 过滤迭代器:在遍历时跳过不符合条件的元素(如只遍历分数大于60分的学生),通过装饰器模式扩展具体迭代器实现。
  • 组合迭代器:遍历嵌套集合(如树形结构),递归调用子节点的迭代器(如TreeSet的遍历)。

最佳实践

建议 理由
优先使用语言内置迭代器 如Java的IteratorSpliterator,避免重复造轮子,利用标准库的健壮性。
避免在迭代中修改集合 迭代过程中直接修改集合(如添加/删除元素)可能导致ConcurrentModificationException(快速失败机制)。
自定义迭代器需实现Iterable 若需支持增强型for循环(for-each),需让具体容器实现Iterable接口并返回迭代器。
明确迭代器的线程安全性 若集合可能被多线程访问,需使用线程安全的迭代器(如CopyOnWriteArrayList的迭代器)。

一句话总结

迭代器模式通过统一遍历接口解耦集合实现与遍历逻辑,使客户端能以一致的方式访问不同集合的元素,是提升代码灵活性和可维护性的经典方案。

如果关注Java设计模式内容,可以查阅作者的其他Java设计模式系列文章。😊


网站公告

今日签到

点亮在社区的每一天
去签到