【设计模式】【行为型模式】迭代器模式(Iterator)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

文章目录

一、入门

什么是迭代器模式?

迭代器模式(Iterator Pattern)是一种行为设计模式,它提供了一种顺序访问聚合对象中元素的方法,而不需要暴露其底层表示。迭代器模式将遍历逻辑从聚合对象中分离出来,使得聚合对象可以专注于数据存储,而迭代器负责遍历。

为什么要迭代器模式?

在没有迭代器模式的情况下,客户端代码需要直接依赖书架的内部结构(如数组或列表)来遍历书籍。这种方式会导致遍历逻辑与书架类耦合。

java 复制代码
// 书籍类
class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

// 书架类
class BookShelf {
    private Book[] books;
    private int size;

    public BookShelf(int capacity) {
        books = new Book[capacity];
        size = 0;
    }

    public void addBook(Book book) {
        if (size < books.length) {
            books[size++] = book;
        }
    }

    // 暴露内部数组
    public Book[] getBooks() {
        return books;
    }

    // 暴露书架大小
    public int getSize() {
        return size;
    }
}

// 客户端代码
public class LibraryWithoutIterator {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(3);
        bookShelf.addBook(new Book("Design Patterns"));
        bookShelf.addBook(new Book("Clean Code"));
        bookShelf.addBook(new Book("Refactoring"));

        // 直接依赖书架的内部结构(数组)进行遍历
        Book[] books = bookShelf.getBooks();
        for (int i = 0; i < bookShelf.getSize(); i++) {
            System.out.println(books[i].getName());
        }
    }
}

存在的问题

  1. 耦合性强:客户端代码直接依赖书架的内部结构(数组),如果书架的存储结构改为链表,客户端代码也需要修改。
  2. 破坏封装性:书架类暴露了内部数据(数组和大小),客户端代码可以直接操作这些数据,可能导致数据不一致。
  3. 无法统一遍历接口:如果图书馆中有多种存储结构(如书架、电子书库等),客户端代码需要为每种结构编写特定的遍历逻辑。

怎么实现迭代器模式?

迭代器模式的组成

  1. 迭代器接口(Iterator Interface) :定义了遍历元素所需的操作,如next()hasNext()等。
  2. 具体迭代器(Concrete Iterator):实现迭代器接口,负责管理当前遍历的位置。
  3. 聚合接口(Aggregate Interface) :定义了创建迭代器的方法,如createIterator()
  4. 具体聚合类(Concrete Aggregate):实现聚合接口,返回一个具体迭代器的实例。

【案例】图书管理 - 改

迭代器接口(Iterator Interface)Iterator迭代器接口,定义遍历聚合对象所需的方法。

java 复制代码
interface Iterator<T> {
    boolean hasNext();
    T next();
}
具体迭代器(Concrete Iterator):BookShelfIterator 类,实现迭代器接口,负责管理当前遍历的位置,并实现具体的遍历逻辑。
// 具体迭代器
class BookShelfIterator implements Iterator<Book> {
    private BookShelf bookShelf; // 关联的具体聚合类
    private int currentIndex = 0; // 当前遍历的位置

    // 构造函数,传入具体聚合类
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
    }

    @Override
    public boolean hasNext() {
        return currentIndex < bookShelf.getSize(); // 判断是否还有下一个元素
    }

    @Override
    public Book next() {
        Book book = bookShelf.getBookAt(currentIndex); // 获取当前元素
        currentIndex++; // 移动游标
        return book;
    }
}

聚合接口(Aggregate Interface) : Aggregate接口,定义创建迭代器的方法。

java 复制代码
// 聚合接口
interface Aggregate<T> {
    Iterator<T> createIterator(); // 创建迭代器
}
具体聚合类(Concrete Aggregate):BookShelf类,实现聚合接口,负责存储和管理数据,并提供创建迭代器的方法。
// 具体聚合类
class BookShelf implements Aggregate<Book> {
    private Book[] books; // 存储书籍的数组
    private int size;      // 当前书籍数量

    // 构造函数,初始化书架容量
    public BookShelf(int capacity) {
        books = new Book[capacity];
        size = 0;
    }

    // 添加书籍
    public void addBook(Book book) {
        if (size < books.length) {
            books[size++] = book;
        }
    }

    // 获取指定位置的书籍
    public Book getBookAt(int index) {
        return books[index];
    }

    // 获取当前书籍数量
    public int getSize() {
        return size;
    }

    // 实现聚合接口,创建迭代器
    @Override
    public Iterator<Book> createIterator() {
        return new BookShelfIterator(this); // 将当前书架对象传递给迭代器
    }
}

Book类

java 复制代码
class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

测试类

java 复制代码
// 客户端代码
public class LibraryDemo {
    public static void main(String[] args) {
        // 创建一个书架
        BookShelf bookShelf = new BookShelf(3);
        bookShelf.addBook(new Book("Design Patterns"));
        bookShelf.addBook(new Book("Clean Code"));
        bookShelf.addBook(new Book("Refactoring"));

        // 创建迭代器
        Iterator<Book> iterator = bookShelf.createIterator();

        // 使用迭代器遍历书架
        System.out.println("Books in BookShelf:");
        while (iterator.hasNext()) {
            Book book = iterator.next();
            System.out.println(book.getName());
        }
    }
}

输出结果

shell 复制代码
Books in BookShelf:
Design Patterns
Clean Code
Refactoring

二、迭代器模式在源码中的运用

Java 集合框架(Java Collections Framework)

Java集合框架迭代器的使用

Java 的集合框架(如 ArrayListLinkedListHashSet 等)广泛使用了迭代器模式。每个集合类都实现了 Iterable 接口,并提供了 iterator() 方法来返回一个迭代器。

java 复制代码
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class JavaCollectionExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // 使用迭代器遍历集合
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Java集合框架迭代器的源码实现

Iterable接口:定义了iterator()方法,用于返回一个迭代器。

java 复制代码
public interface Iterable<T> {
    Iterator<T> iterator();
}

Iterator接口:定义了遍历集合的方法,如hasNext()next()

java 复制代码
public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove(); // 可选操作
}

ArrayList中的迭代器实现:

java 复制代码
public Iterator<E> iterator() {
    return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // 当前遍历的位置
    int lastRet = -1; // 上一次返回的元素索引

    public boolean hasNext() {
        return cursor != size;
    }

    public E next() {
        // 返回当前元素,并移动游标
        // ...
    }

    public void remove() {
        // 删除上一次返回的元素
        // ...
    }
}

三、总结

迭代器模式的优点

  1. 解耦遍历逻辑与聚合对象
    • 将遍历逻辑从聚合对象中分离出来,聚合对象可以专注于数据存储,而迭代器负责遍历。
    • 符合单一职责原则。
  2. 统一遍历接口
    • 提供了一种统一的方式来遍历不同类型的聚合对象(如数组、链表、树等)。
    • 客户端代码无需关心聚合对象的内部结构。
  3. 支持多种遍历方式
    • 可以为同一个聚合对象定义多个迭代器,实现不同的遍历方式(如正序遍历、逆序遍历、深度优先遍历等)。
  4. 增强封装性
    • 隐藏了聚合对象的内部结构,客户端代码只能通过迭代器访问元素,无法直接操作聚合对象的内部数据。
  5. 开闭原则
    • 新增聚合类和迭代器类不会影响现有代码,易于扩展。

迭代器模式的缺点

  1. 增加复杂性
    • 对于简单的聚合对象,使用迭代器模式可能会增加代码复杂性。
    • 如果遍历逻辑非常简单,直接使用 for 循环可能更直观。
  2. 性能开销
    • 迭代器模式可能会引入额外的性能开销,尤其是在遍历大型数据集时。
  3. 不适合频繁修改的聚合对象
    • 如果聚合对象在遍历过程中频繁修改(如添加或删除元素),可能会导致迭代器失效或抛出异常。

迭代器模式的典型应用场景

  1. 集合框架
    • Java 的集合框架(如 ArrayList、LinkedList、HashSet 等)广泛使用了迭代器模式。
  2. 文件系统遍历
    • 遍历文件系统中的目录和文件时,可以使用迭代器模式封装遍历逻辑。
  3. 数据库查询结果遍历
    • 遍历数据库查询结果集时,可以使用迭代器模式提供统一的遍历接口。
  4. 树形结构遍历
    • 遍历树形结构(如 DOM 树、组织结构树等)时,可以使用迭代器模式支持多种遍历方式(如深度优先遍历、广度优先遍历等)。
相关推荐
卡尔特斯2 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源2 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole2 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫3 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide3 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261353 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源3 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
晨米酱4 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
Java中文社群4 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心4 小时前
从零开始学Flink:数据源
java·大数据·后端·flink