Java 设计模式之迭代器模式:优雅遍历集合元素
在日常开发中,我们经常需要遍历各种集合对象(如列表、集合、树等)。如果每个集合都自行实现遍历逻辑,不仅会导致代码冗余,还会暴露内部结构,违背封装原则。迭代器模式(Iterator Pattern)正是为解决这类问题而生,它提供了一种统一的方式来遍历不同集合,同时隐藏底层实现细节。
迭代器模式的核心思想
迭代器模式属于行为型设计模式,它的核心是将集合对象的遍历行为分离出来,封装成独立的迭代器对象,使迭代逻辑与集合本身解耦。这样做的好处是:
- 支持以不同方式遍历同一个集合
- 简化集合类的设计,无需关心遍历实现
- 符合单一职责原则,集合只负责存储数据,迭代器负责遍历
- 可以在遍历过程中安全地修改集合(需特殊处理)
迭代器模式的角色组成
迭代器模式主要包含以下四个角色:
- 抽象迭代器(Iterator):定义遍历元素的接口,通常包含
hasNext()和next()方法 - 具体迭代器(ConcreteIterator):实现抽象迭代器接口,记录当前遍历位置
- 抽象聚合(Aggregate):定义创建迭代器的接口,声明一个
createIterator()方法 - 具体聚合(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接口就是抽象迭代器,而ArrayList、HashSet等集合类则是具体聚合,它们通过iterator()方法返回具体迭代器实现。
例如,我们常用的遍历方式:
List<String> list = new ArrayList<>();
// 添加元素...
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
// 处理元素
}
这种方式正是迭代器模式的典型应用,它使我们可以用统一的方式遍历不同的集合,而不必关心其内部实现。
迭代器模式的适用场景
- 当需要为聚合对象提供多种遍历方式时
- 当需要遍历不同的聚合结构(如数组、链表、树等)时
- 当希望隐藏聚合对象的内部实现,只暴露遍历接口时
- 当需要在遍历过程中对聚合对象进行修改,且不影响遍历过程时
迭代器模式的优缺点
优点:
- 实现了遍历算法与聚合对象的分离
- 可以为一个聚合对象提供多种遍历方式
- 简化了聚合类的设计
- 支持对聚合对象的多种遍历
缺点:
- 增加了类的数量,一定程度上增加了系统复杂度
- 如果聚合对象的结构发生变化,可能需要修改迭代器的实现
总结
迭代器模式通过将遍历逻辑封装在独立的迭代器对象中,实现了聚合对象与遍历算法的解耦。它不仅提供了统一的遍历接口,简化了客户端代码,还保护了聚合对象的内部结构。
在实际开发中,我们很少需要自己实现迭代器模式,因为 Java 集合框架已经为我们提供了完善的迭代器支持。但理解迭代器模式的设计思想,有助于我们更好地使用这些 API,以及在面对复杂集合结构时设计出更灵活、更易维护的代码。