公众号:【CTO成长日记】

Java 设计模式之迭代器模式:优雅遍历集合元素

在日常开发中,我们经常需要遍历各种集合对象(如列表、集合、树等)。如果每个集合都自行实现遍历逻辑,不仅会导致代码冗余,还会暴露内部结构,违背封装原则。迭代器模式(Iterator Pattern)正是为解决这类问题而生,它提供了一种统一的方式来遍历不同集合,同时隐藏底层实现细节。

迭代器模式的核心思想

迭代器模式属于行为型设计模式,它的核心是将集合对象的遍历行为分离出来,封装成独立的迭代器对象,使迭代逻辑与集合本身解耦。这样做的好处是:

  • 支持以不同方式遍历同一个集合
  • 简化集合类的设计,无需关心遍历实现
  • 符合单一职责原则,集合只负责存储数据,迭代器负责遍历
  • 可以在遍历过程中安全地修改集合(需特殊处理)

迭代器模式的角色组成

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

  1. 抽象迭代器(Iterator):定义遍历元素的接口,通常包含hasNext()next()方法
  2. 具体迭代器(ConcreteIterator):实现抽象迭代器接口,记录当前遍历位置
  3. 抽象聚合(Aggregate):定义创建迭代器的接口,声明一个createIterator()方法
  4. 具体聚合(ConcreteAggregate):实现抽象聚合接口,返回具体迭代器实例

迭代器模式的代码实现

下面我们通过一个图书管理系统的例子来实现迭代器模式。

1. 定义抽象迭代器接口

// 抽象迭代器
public interface Iterator {
    // 判断是否还有下一个元素
    boolean hasNext();
    
    // 获取下一个元素
    Object next();
}

2. 定义具体迭代器实现

// 具体迭代器 - 图书迭代器
public class BookIterator implements Iterator {
    private Book[] books;
    private int position; // 当前遍历位置
    
    public BookIterator(Book[] books) {
        this.books = books;
        this.position = 0;
    }
    
    @Override
    public boolean hasNext() {
        return position < books.length && books[position] != null;
    }
    
    @Override
    public Object next() {
        Book book = books[position];
        position++;
        return book;
    }
}

3. 定义抽象聚合接口

// 抽象聚合
public interface Aggregate {
    // 创建迭代器
    Iterator createIterator();
}

4. 定义具体聚合实现

// 图书类
public class Book {
    private String name;
    
    public Book(String name) {
        this.name = name;
    }
    
    public String getName() {
        return name;
    }
}

// 具体聚合 - 图书书架
public class BookShelf implements Aggregate {
    private Book[] books;
    private int last; // 最后一本书的位置
    
    public BookShelf(int maxSize) {
        this.books = new Book[maxSize];
        this.last = 0;
    }
    
    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 createIterator() {
        return new BookIterator(books);
    }
}

5. 客户端使用示例

public class Client {
    public static void main(String[] args) {
        // 创建书架并添加图书
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Java编程思想"));
        bookShelf.appendBook(new Book("设计模式:可复用面向对象软件的基础"));
        bookShelf.appendBook(new Book("深入理解Java虚拟机"));
        bookShelf.appendBook(new Book("Effective Java"));
        
        // 获取迭代器并遍历
        Iterator iterator = bookShelf.createIterator();
        while (iterator.hasNext()) {
            Book book = (Book) iterator.next();
            System.out.println("图书名称:" + book.getName());
        }
    }
}

运行结果:

图书名称:Java编程思想
图书名称:设计模式:可复用面向对象软件的基础
图书名称:深入理解Java虚拟机
图书名称:Effective Java

Java 集合框架中的迭代器模式

实际上,Java 集合框架(Collection Framework)大量使用了迭代器模式。java.util.Iterator接口就是抽象迭代器,而ArrayListHashSet等集合类则是具体聚合,它们通过iterator()方法返回具体迭代器实现。

例如,我们常用的遍历方式:

List<String> list = new ArrayList<>();
// 添加元素...
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    // 处理元素
}

这种方式正是迭代器模式的典型应用,它使我们可以用统一的方式遍历不同的集合,而不必关心其内部实现。

迭代器模式的适用场景

  • 当需要为聚合对象提供多种遍历方式时
  • 当需要遍历不同的聚合结构(如数组、链表、树等)时
  • 当希望隐藏聚合对象的内部实现,只暴露遍历接口时
  • 当需要在遍历过程中对聚合对象进行修改,且不影响遍历过程时

迭代器模式的优缺点

优点:

  • 实现了遍历算法与聚合对象的分离
  • 可以为一个聚合对象提供多种遍历方式
  • 简化了聚合类的设计
  • 支持对聚合对象的多种遍历

缺点:

  • 增加了类的数量,一定程度上增加了系统复杂度
  • 如果聚合对象的结构发生变化,可能需要修改迭代器的实现

总结

迭代器模式通过将遍历逻辑封装在独立的迭代器对象中,实现了聚合对象与遍历算法的解耦。它不仅提供了统一的遍历接口,简化了客户端代码,还保护了聚合对象的内部结构。

在实际开发中,我们很少需要自己实现迭代器模式,因为 Java 集合框架已经为我们提供了完善的迭代器支持。但理解迭代器模式的设计思想,有助于我们更好地使用这些 API,以及在面对复杂集合结构时设计出更灵活、更易维护的代码。

原文:CTO成长日记

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐