迭代器模式详解
一、迭代器模式概述
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。迭代器模式将遍历逻辑从聚合对象中分离出来,使得聚合对象和遍历算法可以独立变化。
核心特点
- 统一遍历接口:提供一致的遍历方式
- 解耦集合与遍历:集合结构变化不影响遍历代码
- 支持多种遍历:可定义不同的迭代策略
- 简化集合接口:集合只需提供创建迭代器的方法
二、迭代器模式的结构
主要角色
- Iterator:迭代器接口,定义访问和遍历元素的接口
- ConcreteIterator:具体迭代器,实现迭代器接口
- Aggregate:聚合接口,定义创建迭代器的方法
- ConcreteAggregate:具体聚合,实现创建迭代器的方法
三、迭代器模式的实现
1. 基本实现
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体聚合 - 数组集合
public class ArrayCollection<T> implements Aggregate<T> {
private T[] items;
public ArrayCollection(T[] items) {
this.items = items;
}
public Iterator<T> createIterator() {
return new ArrayIterator<T>(items);
}
}
// 具体迭代器 - 数组迭代器
public class ArrayIterator<T> implements Iterator<T> {
private T[] items;
private int position = 0;
public ArrayIterator(T[] items) {
this.items = items;
}
public boolean hasNext() {
return position < items.length;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items[position++];
}
}
// 使用示例
String[] names = {"Alice", "Bob", "Charlie"};
Aggregate<String> collection = new ArrayCollection<>(names);
Iterator<String> iterator = collection.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
2. 支持双向遍历的迭代器
// 扩展的迭代器接口
public interface BidirectionalIterator<T> extends Iterator<T> {
boolean hasPrevious();
T previous();
void reset();
}
// 双向数组迭代器
public class BidirectionalArrayIterator<T> implements BidirectionalIterator<T> {
private T[] items;
private int position = 0;
public BidirectionalArrayIterator(T[] items) {
this.items = items;
}
public boolean hasNext() {
return position < items.length;
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items[position++];
}
public boolean hasPrevious() {
return position > 0;
}
public T previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
return items[--position];
}
public void reset() {
position = 0;
}
}
四、迭代器模式的应用场景
1. 自定义集合遍历
// 树节点
public class TreeNode<T> {
private T value;
private List<TreeNode<T>> children = new ArrayList<>();
public TreeNode(T value) {
this.value = value;
}
public void addChild(TreeNode<T> child) {
children.add(child);
}
// 创建深度优先迭代器
public Iterator<T> createDepthFirstIterator() {
return new DepthFirstIterator<>(this);
}
// 创建广度优先迭代器
public Iterator<T> createBreadthFirstIterator() {
return new BreadthFirstIterator<>(this);
}
}
// 深度优先迭代器
public class DepthFirstIterator<T> implements Iterator<T> {
private Stack<TreeNode<T>> stack = new Stack<>();
public DepthFirstIterator(TreeNode<T> root) {
stack.push(root);
}
public boolean hasNext() {
return !stack.isEmpty();
}
public T next() {
TreeNode<T> node = stack.pop();
for (int i = node.children.size() - 1; i >= 0; i--) {
stack.push(node.children.get(i));
}
return node.value;
}
}
2. 文件系统遍历
// 文件系统条目接口
public interface FileSystemItem {
String getName();
Iterator<FileSystemItem> createIterator();
}
// 文件类
public class File implements FileSystemItem {
private String name;
public File(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Iterator<FileSystemItem> createIterator() {
return Collections.emptyIterator();
}
}
// 目录类
public class Directory implements FileSystemItem {
private String name;
private List<FileSystemItem> items = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void addItem(FileSystemItem item) {
items.add(item);
}
public String getName() {
return name;
}
public Iterator<FileSystemItem> createIterator() {
return new DirectoryIterator(items);
}
}
// 目录迭代器
public class DirectoryIterator implements Iterator<FileSystemItem> {
private Stack<Iterator<FileSystemItem>> stack = new Stack<>();
public DirectoryIterator(List<FileSystemItem> items) {
stack.push(items.iterator());
}
public boolean hasNext() {
if (stack.isEmpty()) return false;
Iterator<FileSystemItem> iterator = stack.peek();
if (iterator.hasNext()) {
return true;
} else {
stack.pop();
return hasNext();
}
}
public FileSystemItem next() {
Iterator<FileSystemItem> iterator = stack.peek();
FileSystemItem item = iterator.next();
if (item instanceof Directory) {
stack.push(item.createIterator());
}
return item;
}
}
3. 数据库结果集遍历
// 数据库结果集接口
public interface ResultSet<T> {
Iterator<T> iterator();
}
// 分页结果集实现
public class PagedResultSet<T> implements ResultSet<T> {
private PageFetcher<T> fetcher;
private int pageSize;
public PagedResultSet(PageFetcher<T> fetcher, int pageSize) {
this.fetcher = fetcher;
this.pageSize = pageSize;
}
public Iterator<T> iterator() {
return new PagedIterator<>(fetcher, pageSize);
}
}
// 分页迭代器
public class PagedIterator<T> implements Iterator<T> {
private PageFetcher<T> fetcher;
private int pageSize;
private List<T> currentPage;
private int currentIndex;
private int currentPageNumber;
public PagedIterator(PageFetcher<T> fetcher, int pageSize) {
this.fetcher = fetcher;
this.pageSize = pageSize;
this.currentPageNumber = 0;
loadNextPage();
}
public boolean hasNext() {
if (currentIndex < currentPage.size()) {
return true;
}
return currentPage.size() == pageSize; // 如果不满一页,说明没有下一页
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
if (currentIndex >= currentPage.size()) {
loadNextPage();
currentIndex = 0;
}
return currentPage.get(currentIndex++);
}
private void loadNextPage() {
currentPage = fetcher.fetchPage(currentPageNumber++, pageSize);
currentIndex = 0;
}
}
五、迭代器模式的变体
1. 内部类迭代器
public class BookCollection implements Iterable<Book> {
private List<Book> books = new ArrayList<>();
public void addBook(Book book) {
books.add(book);
}
public Iterator<Book> iterator() {
return new BookIterator();
}
// 内部类实现迭代器
private class BookIterator implements Iterator<Book> {
private int currentIndex = 0;
public boolean hasNext() {
return currentIndex < books.size();
}
public Book next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return books.get(currentIndex++);
}
}
}
2. 过滤迭代器
public class FilteringIterator<T> implements Iterator<T> {
private Iterator<T> source;
private Predicate<T> predicate;
private T nextItem;
private boolean hasNext;
public FilteringIterator(Iterator<T> source, Predicate<T> predicate) {
this.source = source;
this.predicate = predicate;
findNext();
}
public boolean hasNext() {
return hasNext;
}
public T next() {
if (!hasNext) {
throw new NoSuchElementException();
}
T result = nextItem;
findNext();
return result;
}
private void findNext() {
hasNext = false;
while (source.hasNext()) {
nextItem = source.next();
if (predicate.test(nextItem)) {
hasNext = true;
break;
}
}
}
}
六、迭代器模式的优缺点
优点
- 单一职责原则:将遍历算法与集合分离
- 开闭原则:可以新增迭代器而不修改集合
- 并行遍历:可同时使用多个迭代器遍历同一集合
- 延迟加载:可按需获取元素,节省内存
缺点
- 简单集合可能过度设计:对简单集合使用迭代器可能增加复杂度
- 效率可能降低:某些情况下比直接遍历效率低
- 实现复杂:某些复杂数据结构的迭代器实现较困难
七、最佳实践
- 优先实现Iterable接口:使集合支持for-each循环
- 考虑线程安全:多线程环境下的迭代器安全性
- 支持快速失败:迭代过程中检测集合修改
- 资源清理:实现Closeable接口释放资源
- 组合使用:与过滤器、映射器等组合使用
八、总结
迭代器模式是集合遍历的标准解决方案,特别适用于:
- 需要统一遍历不同结构的集合
- 需要支持多种遍历方式
- 需要隐藏集合内部实现
- 需要延迟加载或分批处理数据
在实际开发中,迭代器模式常见于:
- Java集合框架(Collection.iterator())
- 数据库结果集遍历
- 树形结构遍历
- 文件系统遍历
- 分页数据加载
正确使用迭代器模式可以提高代码的复用性和灵活性,但对于简单遍历需求,直接使用for循环可能更简洁。