23种设计模式一迭代器模式

一、引言

迭代子模式 (Iterator Pattern),又称为迭代器模式,是设计模式中行为型模式的一种。它提供了一种顺序访问集合对象中各个元素的方法,而又不需要暴露该对象的内部表示。

在Java开发中,我们经常需要遍历各种集合类型,如List、Set、Map等。迭代器模式为我们提供了一种统一的遍历接口 ,使得我们可以用相同的方式遍历不同的集合结构,这大大提高了代码的复用性灵活性

1.1 模式定义

迭代器模式定义如下:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

1.2 在Java中的重要性

  • Java集合框架广泛使用迭代器模式
  • 为不同集合类型提供统一的遍历接口
  • 支持多种遍历策略(正向、反向、并发遍历等)
  • 是现代编程语言中不可或缺的设计模式之一

二、核心概念

迭代器模式主要包含以下四个核心角色:

2.1 角色组成

(1)抽象迭代器(Iterator)

定义遍历聚合对象所需的接口,通常包含以下方法:

  • hasNext():判断是否还有下一个元素
  • next():获取下一个元素
  • remove():可选操作,删除当前元素

(2)具体迭代器(ConcreteIterator)

实现抽象迭代器接口,跟踪遍历过程中的当前位置,负责管理遍历状态。

(3)抽象聚合(Aggregate)

定义创建相应迭代器对象的接口,通常声明一个iterator()方法。

(4)具体聚合(ConcreteAggregate)

实现抽象聚合接口,返回一个具体迭代器的实例。

2.2 类图说明

复制代码
┌─────────────────┐         ┌─────────────────┐
│   <<interface>>│         │   <<interface>>│
│    Iterator     │         │    Aggregate    │
├─────────────────┤         ├─────────────────┤
│ +hasNext():bool │         │ +iterator():Iterator│
│ +next():Object  │         └─────────────────┘
│ +remove():void  │                  △
└─────────────────┘                  │
         △                          │
         │                ┌─────────────────┐
         │                │ConcreteAggregate│
┌─────────────────┐       ├─────────────────┤
│ConcreteIterator│       │ +iterator():... │
├─────────────────┤       └─────────────────┘
│ +hasNext():bool │                │
│ +next():Object  │                │
│ +remove():void  │                │
├─────────────────┤                │
│ -position:int   │                │
└─────────────────┘                │
         │                         │
         └─────────────────────────┘

三、实现步骤

下面通过一个完整的Java代码示例来展示迭代器模式的实现过程。我们将实现一个自定义的**书架(BookShelf)**及其迭代器。

3.1 实现步骤概述

  1. 定义Iterator接口
  2. 定义Aggregate接口
  3. 实现具体迭代器BookShelfIterator
  4. 实现具体聚合BookShelf
  5. 定义元素对象Book
  6. 客户端测试代码

3.2 完整代码实现

(1)定义Iterator接口

java 复制代码
/**
 * 迭代器接口
 */
public interface Iterator {
    /**
     * 判断是否有下一个元素
     * @return true表示还有下一个元素,false表示已经到达末尾
     */
    boolean hasNext();
    
    /**
     * 获取下一个元素
     * @return 下一个元素对象
     */
    Object next();
}

(2)定义Aggregate接口

java 复制代码
/**
 * 聚合接口,定义创建迭代器的方法
 */
public interface Aggregate {
    /**
     * 创建对应的迭代器
     * @return 迭代器对象
     */
    Iterator iterator();
}

(3)定义Book类

java 复制代码
/**
 * 书籍类,作为集合中的元素
 */
public class Book {
    private String name;
    
    public Book(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
    
    @Override
    public String toString() {
        return "《" + name + "》";
    }
}

(4)实现具体迭代器BookShelfIterator

java 复制代码
/**
 * 书架迭代器,具体迭代器实现
 */
public class BookShelfIterator implements Iterator {
    private BookShelf bookShelf;
    private int index;
    
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = 0;
    }
    
    @Override
    public boolean hasNext() {
        return index < bookShelf.getLength();
    }
    
    @Override
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

(5)实现具体聚合BookShelf

java 复制代码
/**
 * 书架类,具体聚合实现
 */
public class BookShelf implements Aggregate {
    private Book[] books;
    private int last = 0;
    
    public BookShelf(int maxSize) {
        this.books = new Book[maxSize];
    }
    
    public Book getBookAt(int index) {
        return books[index];
    }
    
    public void appendBook(Book book) {
        this.books[last] = book;
        last++;
    }
    
    public int getLength() {
        return last;
    }
    
    @Override
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}

(6)客户端测试代码

java 复制代码
/**
 * 客户端测试类
 */
public class Main {
    public static void main(String[] args) {
        // 创建书架
        BookShelf bookShelf = new BookShelf(4);
        
        // 添加书籍
        bookShelf.appendBook(new Book("Java编程思想"));
        bookShelf.appendBook(new Book("设计模式"));
        bookShelf.appendBook(new Book("算法导论"));
        bookShelf.appendBook(new Book("重构:改善既有代码的设计"));
        
        // 使用迭代器遍历书架
        System.out.println("=== 书架书籍列表 ===");
        Iterator iterator = bookShelf.iterator();
        while (iterator.hasNext()) {
            Book book = (Book) iterator.next();
            System.out.println(book);
        }
    }
}

(7)运行结果

复制代码
=== 书架书籍列表 ===
《Java编程思想》
《设计模式》
《算法导论》
《重构:改善既有代码的设计》

3.3 泛型版本实现(推荐)

为了提高类型安全性,我们可以使用泛型来改进上述实现:

java 复制代码
/**
 * 泛型迭代器接口
 */
public interface Iterator<T> {
    boolean hasNext();
    T next();
}

/**
 * 泛型书架迭代器
 */
public class BookShelfIterator implements Iterator<Book> {
    private BookShelf bookShelf;
    private int index;
    
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = 0;
    }
    
    @Override
    public boolean hasNext() {
        return index < bookShelf.getLength();
    }
    
    @Override
    public Book next() {
        return bookShelf.getBookAt(index++);
    }
}

/**
 * 泛型客户端代码
 */
public class Main {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Java编程思想"));
        bookShelf.appendBook(new Book("设计模式"));
        
        // 使用泛型迭代器,无需类型转换
        Iterator<Book> iterator = bookShelf.iterator();
        while (iterator.hasNext()) {
            Book book = iterator.next(); // 直接获得Book类型
            System.out.println(book);
        }
    }
}

四、应用场景

4.1 典型应用场景

(1)集合遍历

最常见的就是遍历各种集合类型,如List、Set等。

java 复制代码
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Go");

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

(2)数据库查询结果集

JDBC中的ResultSet本质上也是一个迭代器。

java 复制代码
// ResultSet 迭代模式示例
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

while (rs.next()) { // 类似 hasNext() + next()
    String name = rs.getString("name");
    System.out.println(name);
}

(3)文件系统遍历

遍历文件夹中的文件。

java 复制代码
// 伪代码示例
FileIterator fileIterator = new FileIterator("/path/to/directory");
while (fileIterator.hasNext()) {
    File file = fileIterator.next();
    processFile(file);
}

(4)菜单导航

树形结构的菜单遍历。

java 复制代码
// 菜单迭代器示例
MenuItemIterator menuIterator = restaurantMenu.iterator();
while (menuIterator.hasNext()) {
    MenuItem item = menuIterator.next();
    displayMenuItem(item);
}

(5)反向迭代

某些场景需要反向遍历集合。

java 复制代码
// 反向迭代器示例
Iterator<String> reverseIterator = new ReverseIterator<>(list);
while (reverseIterator.hasNext()) {
    System.out.println(reverseIterator.next());
}

4.2 应用优势

  1. 简化集合遍历:提供统一的遍历方式,简化客户端代码
  2. 封装内部结构:客户端无需知道集合的内部实现细节
  3. 支持多种遍历策略:可以轻松实现不同的遍历方式(正向、反向、跳跃等)
  4. 符合单一职责原则:将遍历逻辑从集合类中分离出来

五、优缺点分析

5.1 优点

(1)符合单一职责原则

迭代器模式将遍历操作聚合对象的职责分离,使得聚合对象专注于数据管理,迭代器专注于遍历逻辑。

(2)符合开闭原则

当需要新增遍历方式时,只需新增迭代器类,无需修改聚合类的代码。

(3)简化客户端代码

客户端只需要与Iterator接口交互,无需了解聚合对象的内部结构。

(4)支持多种遍历方式**

可以同时存在多个迭代器对象,支持正向、反向、跳跃等多种遍历策略。

java 复制代码
// 同时使用多个迭代器
List<String> list = Arrays.asList("A", "B", "C", "D");
Iterator<String> forward = list.iterator();
Iterator<String> reverse = new ReverseIterator<>(list);

// 两个迭代器互不干扰

(5)封装性良好

客户端只能通过迭代器访问集合元素,无法直接操作集合内部结构,提高了安全性。

5.2 缺点

(1)增加类的数量

每个聚合类都需要对应一个迭代器类,增加了系统的复杂性。

复制代码
传统方式:1个集合类
迭代器模式:1个集合类 + 1个迭代器类

(2)对于简单集合可能过度设计

对于简单的数组遍历,使用迭代器模式可能是"杀鸡用牛刀"。

(3)存储遍历状态需要额外空间

迭代器需要记录当前遍历位置,对于某些数据结构可能需要额外的存储空间。

java 复制代码
// 双向链表的迭代器可能需要存储更多状态
public class LinkedListIterator {
    private Node currentNode;      // 当前节点
    private Node lastReturned;     // 最后返回的节点
    private int expectedModCount;   // 修改计数器
}

(4)并发遍历可能存在问题**

如果多个迭代器同时遍历同一个集合,且集合在遍历过程中被修改,可能产生不可预期的结果。

java 复制代码
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");

Iterator<String> it1 = list.iterator();
Iterator<String> it2 = list.iterator();

it1.next();
list.add("C"); // 修改集合
it2.next();    // 可能抛出 ConcurrentModificationException

六、JDK中的应用

Java集合框架是迭代器模式的典型应用,几乎所有的集合类都实现了迭代器模式。

6.1 Iterator接口

JDK中定义的核心迭代器接口:

java 复制代码
package java.util;

/**
 * 集合的迭代器接口
 */
public interface Iterator<E> {
    /**
     * 判断是否还有下一个元素
     */
    boolean hasNext();
    
    /**
     * 返回下一个元素
     */
    E next();
    
    /**
     * 从底层集合中移除此迭代器返回的最后一个元素(可选操作)
     */
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    /**
     * 对每个剩余元素执行给定操作(Java 8新增)
     */
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

6.2 Iterable接口

所有可迭代集合都需要实现此接口:

java 复制代码
package java.util;

/**
 * 实现此接口允许对象成为 "foreach" 语句的目标
 */
public interface Iterable<T> {
    /**
     * 返回一个类型为 T 的元素的迭代器
     */
    Iterator<T> iterator();
    
    /**
     * Java 8新增:默认的forEach方法
     */
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
    
    /**
     * Java 8新增:返回并行迭代器
     */
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

6.3 典型实现示例

(1)ArrayList的迭代器实现

java 复制代码
// ArrayList内部类
private class Itr implements Iterator<E> {
    int cursor;       // 下一个要返回的元素的索引
    int lastRet = -1; // 上一个返回的元素的索引;如果没有则为 -1
    int expectedModCount = modCount; // 修改计数器
    
    public boolean hasNext() {
        return cursor != size;
    }
    
    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    
    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();
        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    
    // 快速失败机制检查
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

(2)ListIterator接口(增强版迭代器)

java 复制代码
package java.util;

/**
 * 列表迭代器,允许程序员在任一方向遍历列表
 */
public interface ListIterator<E> extends Iterator<E> {
    // 继承自Iterator的方法
    boolean hasNext();
    E next();
    
    // 新增的反向遍历方法
    boolean hasPrevious();
    E previous();
    int nextIndex();
    int previousIndex();
    
    // 修改操作
    void set(E e);
    void add(E e);
}

6.4 快速失败机制(Fail-Fast)

Java集合框架中的迭代器实现了快速失败机制,用于检测并发修改:

java 复制代码
public class FailFastExample {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String str = it.next();
            if (str.equals("B")) {
                // 在遍历过程中修改集合
                list.remove(str); // 抛出 ConcurrentModificationException
            }
        }
    }
}

快速失败机制的原理

  • 集合内部维护一个modCount(修改计数器)
  • 迭代器创建时记录当前的modCount
  • 每次迭代时检查集合的modCount是否改变
  • 如果发现变化,立即抛出ConcurrentModificationException

6.5 JDK中的迭代器使用示例

java 复制代码
public class JDKIteratorExample {
    public static void main(String[] args) {
        // List迭代器示例
        System.out.println("=== List迭代器 ===");
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("Go");
        
        // 方式1:使用Iterator
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        
        // 方式2:使用for-each(语法糖,底层也是迭代器)
        System.out.println("\n=== for-each循环 ===");
        for (String lang : list) {
            System.out.println(lang);
        }
        
        // 方式3:使用ListIterator(支持双向遍历)
        System.out.println("\n=== ListIterator反向遍历 ===");
        ListIterator<String> lit = list.listIterator(list.size());
        while (lit.hasPrevious()) {
            System.out.println(lit.previous());
        }
        
        // Set迭代器示例
        System.out.println("\n=== Set迭代器 ===");
        Set<Integer> set = new HashSet<>();
        set.add(3);
        set.add(1);
        set.add(2);
        
        Iterator<Integer> setIt = set.iterator();
        while (setIt.hasNext()) {
            System.out.println(setIt.next());
        }
        
        // Map迭代器示例
        System.out.println("\n=== Map迭代器 ===");
        Map<String, Integer> map = new HashMap<>();
        map.put("Apple", 10);
        map.put("Banana", 20);
        map.put("Orange", 15);
        
        // 遍历Key
        System.out.println("--- 遍历Key ---");
        Iterator<String> keyIterator = map.keySet().iterator();
        while (keyIterator.hasNext()) {
            String key = keyIterator.next();
            System.out.println(key + ": " + map.get(key));
        }
        
        // 遍历Entry
        System.out.println("--- 遍历Entry ---");
        Iterator<Map.Entry<String, Integer>> entryIterator = 
            map.entrySet().iterator();
        while (entryIterator.hasNext()) {
            Map.Entry<String, Integer> entry = entryIterator.next();
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

七、总结

7.1 核心要点回顾

迭代器模式是一种简单而强大的设计模式,它通过以下方式解决了集合遍历问题:

方面 说明
核心思想 将遍历操作从集合对象中分离出来
主要角色 Iterator(迭代器)、Aggregate(聚合)、具体实现类
关键优势 统一接口、封装细节、支持多种遍历策略
JDK应用 Collection框架、Iterable接口、Iterator接口

7.2 使用建议

(1)何时使用迭代器模式?

推荐使用的场景

  • 需要为聚合对象提供多种遍历方式
  • 需要遍历复杂的聚合结构(如树、图)
  • 希望隐藏聚合对象的内部实现细节
  • 需要支持同一个聚合对象上的多个遍历

不推荐使用的场景

  • 简单的数组遍历
  • 只有单一遍历方式且不会变化的场景
  • 性能要求极高的场景(避免额外开销)

(2)最佳实践

  1. 优先使用泛型:提高类型安全性

    java 复制代码
    Iterator<Book> it = bookShelf.iterator(); // 推荐
    Iterator it = bookShelf.iterator();       // 不推荐
  2. 考虑使用for-each语法:简化代码

    java 复制代码
    // 推荐:简洁明了
    for (Book book : bookShelf) {
        System.out.println(book);
    }
  3. 注意并发修改问题:使用迭代器的remove方法

    java 复制代码
    Iterator<String> it = list.iterator();
    while (it.hasNext()) {
        String str = it.next();
        if (str.equals("B")) {
            it.remove(); // 正确的删除方式
        }
    }
  4. 实现合适的迭代器类型:根据需要选择Iterator或ListIterator

    java 复制代码
    ListIterator<Book> lit = list.listIterator(); // 支持双向遍历

(3)扩展思考

与Java 8 Stream API的关系

Java 8引入的Stream API可以看作是迭代器模式的增强版

java 复制代码
// 传统迭代器方式
Iterator<Book> it = bookList.iterator();
while (it.hasNext()) {
    Book book = it.next();
    if (book.getPrice() > 50) {
        System.out.println(book.getName());
    }
}

// Stream API方式(函数式编程风格)
bookList.stream()
       .filter(book -> book.getPrice() > 50)
       .map(Book::getName)
       .forEach(System.out::println);

Stream API提供了:

  • 更强的声明式编程能力
  • 支持并行处理
  • 丰富的中间操作终端操作
  • 更好的性能优化潜力

但这并不意味着迭代器模式过时了,它们各有适用场景:

  • 迭代器:适合需要精细控制遍历过程的场景
  • Stream:适合声明式的数据处理流水线

7.3 结语

迭代器模式是设计模式中应用最广泛的模式之一,它体现了封装变化单一职责的设计原则。通过学习和掌握迭代器模式,我们不仅能够更好地理解Java集合框架的设计思想,还能在自己的项目中灵活运用这一模式,编写出更加优雅、可维护的代码。

在Java开发中,合理使用迭代器模式可以:

  • 提高代码的可读性可维护性
  • 增强模块化程度
  • 实现高内聚、低耦合的设计目标
  • 为后续的扩展优化提供良好基础
相关推荐
驴儿响叮当20105 小时前
设计模式之策略模式
设计模式·策略模式
驴儿响叮当20107 小时前
设计模式之中介模式
设计模式
驴儿响叮当201010 小时前
设计模式之命令模式
设计模式·命令模式
驴儿响叮当201013 小时前
设计模式之适配器模式
设计模式·适配器模式
HEU_firejef13 小时前
设计模式——代理模式
设计模式·代理模式
Coder_Boy_14 小时前
从单体并发工具类到分布式并发:思想演进与最佳实践(二)
java·spring boot·分布式·微服务·设计模式
geovindu1 天前
python: Memento Pattern
开发语言·python·设计模式·备忘录模式
HEU_firejef1 天前
设计模式——单例模式
单例模式·设计模式
电子科技圈1 天前
SmartDV与Mirabilis Design宣布就SmartDV IP系统级模型达成战略合作
大数据·设计模式·软件工程