1. 迭代器模式:为什么我们需要它?
想象一下这个场景:你正在开发一个电商平台的后台系统,商品数据以不同形式存储——MySQL数据库中的热销商品、Redis缓存里的促销商品、ElasticSearch里的全量商品。现在需要实现一个"商品搜索"功能,要求能统一遍历这些异构数据源。你会怎么做?
这就是迭代器模式(Iterator Pattern)的典型应用场景。作为行为型设计模式之一,它提供了一种统一的方法来顺序访问聚合对象中的各个元素,而又不暴露其底层表示。换句话说,迭代器模式让遍历逻辑与数据结构解耦。
关键理解:迭代器模式不是简单的for循环替代品,而是解决"如何用统一接口遍历异构集合"的架构级方案
在Java集合框架中,Iterator接口就是最经典的实现。但迭代器模式的价值远不止于此——当你的系统面临以下情况时,就该考虑它了:
- 需要统一遍历不同类型的数据结构(数组、链表、树、图等)
- 需要对同一集合提供多种遍历方式(正序、逆序、过滤等)
- 需要隐藏集合的内部复杂实现(如数据库分页查询)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 迭代器模式的核心结构解析
2.1 标准UML类图实现
迭代器模式的经典实现包含四个关键角色:
java复制// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
void remove(); // 可选
}
// 聚合对象接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体迭代器
public class ConcreteIterator implements Iterator<T> {
private ConcreteAggregate aggregate;
private int index = 0;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
}
@Override
public boolean hasNext() {
return index < aggregate.size();
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
return aggregate.get(index++);
}
}
// 具体聚合类
public class ConcreteAggregate implements Aggregate<T> {
private List<T> items = new ArrayList<>();
@Override
public Iterator<T> createIterator() {
return new ConcreteIterator(this);
}
// 其他集合操作方法...
}
2.2 现代语言中的演进形式
随着编程语言的发展,迭代器模式有了更多优雅的实现方式:
C#的yield return语法:
csharp复制public class DaysOfWeek : IEnumerable {
public IEnumerator GetEnumerator() {
yield return "Monday";
yield return "Tuesday";
// ...
}
}
Java 8的Stream API:
java复制List<String> list = Arrays.asList("a", "b", "c");
list.stream().iterator(); // 隐式迭代器
C++的STL迭代器:
cpp复制std::vector<int> vec{1,2,3};
for(auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << std::endl;
}
3. 实战:实现一个跨数据源的商品迭代器
让我们回到开头的电商案例,实现一个能同时遍历数据库、缓存和搜索引擎的商品迭代器:
3.1 定义统一商品模型
java复制public class Product {
private String id;
private String name;
private BigDecimal price;
// 其他字段及getter/setter
}
3.2 抽象迭代器接口
java复制public interface ProductIterator extends Iterator<Product> {
int getTotalCount(); // 扩展方法:获取总数
void setFilter(Predicate<Product> filter); // 设置过滤条件
}
3.3 实现具体迭代器
MySQL商品迭代器:
java复制public class MySQLProductIterator implements ProductIterator {
private Connection conn;
private ResultSet rs;
private Predicate<Product> filter;
private Product nextProduct;
public MySQLProductIterator(Connection conn) {
this.conn = conn;
reset();
}
private void reset() {
try {
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
rs = stmt.executeQuery("SELECT * FROM products");
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean hasNext() {
try {
while (rs.next()) {
Product p = mapRowToProduct(rs);
if (filter == null || filter.test(p)) {
nextProduct = p;
return true;
}
}
return false;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public Product next() {
if (nextProduct == null && !hasNext()) {
throw new NoSuchElementException();
}
Product result = nextProduct;
nextProduct = null;
return result;
}
}
Redis商品迭代器(使用SCAN命令):
java复制public class RedisProductIterator implements ProductIterator {
private Jedis jedis;
private ScanResult<String> scanResult;
private Predicate<Product> filter;
public RedisProductIterator(Jedis jedis) {
this.jedis = jedis;
this.scanResult = jedis.scan("0");
}
@Override
public boolean hasNext() {
while (true) {
if (scanResult.getResult().isEmpty()) {
if (scanResult.getCursor().equals("0")) {
return false;
}
scanResult = jedis.scan(scanResult.getCursor());
continue;
}
String key = scanResult.getResult().remove(0);
Product p = deserialize(jedis.get(key));
if (filter == null || filter.test(p)) {
return true;
}
}
}
}
3.4 组合迭代器的实现
java复制public class CompositeProductIterator implements ProductIterator {
private List<ProductIterator> iterators;
private int currentIndex = 0;
@Override
public boolean hasNext() {
while (currentIndex < iterators.size()) {
if (iterators.get(currentIndex).hasNext()) {
return true;
}
currentIndex++;
}
return false;
}
@Override
public Product next() {
if (!hasNext()) throw new NoSuchElementException();
return iterators.get(currentIndex).next();
}
}
4. 迭代器模式的高级应用技巧
4.1 延迟加载与分页优化
在处理大数据集时,直接实现hasNext()和next()可能导致性能问题。我们可以结合分页机制:
java复制public class PagedProductIterator implements ProductIterator {
private int pageSize = 100;
private int currentPage = 0;
private List<Product> currentBatch;
private int indexInBatch = 0;
private void loadNextBatch() {
currentBatch = productService.getProducts(currentPage, pageSize);
currentPage++;
indexInBatch = 0;
}
@Override
public boolean hasNext() {
if (currentBatch == null ||
(indexInBatch >= currentBatch.size() && currentBatch.size() == pageSize)) {
loadNextBatch();
}
return indexInBatch < currentBatch.size();
}
}
4.2 线程安全迭代器实现
在多线程环境下,需要特别注意迭代器的线程安全问题:
java复制public class SynchronizedProductIterator implements ProductIterator {
private final Object lock = new Object();
private ProductIterator delegate;
@Override
public boolean hasNext() {
synchronized (lock) {
return delegate.hasNext();
}
}
@Override
public Product next() {
synchronized (lock) {
return delegate.next();
}
}
}
4.3 基于Fluent API的链式调用
借鉴现代API设计思想,我们可以让迭代器更易用:
java复制public interface FluentProductIterator extends ProductIterator {
FluentProductIterator filter(Predicate<Product> filter);
FluentProductIterator sort(Comparator<Product> comparator);
FluentProductIterator limit(int maxSize);
}
// 使用示例
productIterator
.filter(p -> p.getPrice().compareTo(BigDecimal.valueOf(100)) > 0)
.sort(Comparator.comparing(Product::getPrice).reversed())
.limit(10)
.forEachRemaining(System.out::println);
5. 模式对比:迭代器与其他行为模式
5.1 迭代器 vs 访问者模式
虽然两者都用于遍历对象结构,但有本质区别:
- 迭代器:关注如何遍历,不关心元素操作
- 访问者:将操作与数据结构分离,通过"双重分发"实现
5.2 迭代器 vs 责任链模式
责任链模式中的处理器链也可以看作是一种特殊的迭代器,但:
- 迭代器保证访问每个元素
- 责任链可能在某个处理器处提前终止
5.3 与函数式编程的结合
在现代语言中,迭代器模式常与函数式特性结合:
java复制// Java Stream的惰性求值
products.stream()
.filter(p -> p.getStock() > 0)
.map(Product::getName)
.forEach(System.out::println);
// C# LINQ的延迟执行
var query = from p in products
where p.Price > 100
select p.Name;
6. 实际项目中的经验教训
6.1 性能陷阱:嵌套迭代器
我曾在一个订单处理系统中遇到性能问题,最终发现是多重嵌套迭代导致的:
java复制// 反例:O(n^3)时间复杂度
orders.forEach(order -> {
order.getItems().forEach(item -> {
productInventory.getProducts().forEach(p -> {
if (p.getId().equals(item.getProductId())) {
// 处理逻辑
}
});
});
});
优化方案:
- 使用
Map提前建立索引 - 采用批量查询代替逐条检查
- 对迭代过程进行短路优化
6.2 内存泄漏:未关闭的资源迭代器
特别是数据库游标类型的迭代器,必须确保正确关闭:
java复制try (ProductIterator iterator = createProductIterator()) {
while (iterator.hasNext()) {
process(iterator.next());
}
} // 自动调用iterator.close()
6.3 设计过度:不必要的迭代器抽象
不是所有集合都需要迭代器抽象,简单场景直接使用语言内置的迭代机制更合适:
java复制// 足够简单时不需要专门实现迭代器
for (Product p : products) {
System.out.println(p);
}
判断是否需要专门实现迭代器的标准:
- 遍历逻辑是否复杂(如多条件跳转)
- 是否需要支持多种遍历方式
- 数据源是否异构或需要延迟加载
7. 模式变体与扩展实现
7.1 树形结构迭代器
对于树形数据,可以实现多种遍历方式的迭代器:
java复制// 深度优先迭代器
public class DepthFirstTreeIterator<T> implements Iterator<T> {
private Deque<TreeNode<T>> stack = new ArrayDeque<>();
public DepthFirstTreeIterator(TreeNode<T> root) {
stack.push(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public T next() {
TreeNode<T> node = stack.pop();
for (int i = node.childrenCount() - 1; i >= 0; i--) {
stack.push(node.getChild(i));
}
return node.getValue();
}
}
// 广度优先迭代器
public class BreadthFirstTreeIterator<T> implements Iterator<T> {
private Queue<TreeNode<T>> queue = new LinkedList<>();
public BreadthFirstTreeIterator(TreeNode<T> root) {
queue.offer(root);
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
@Override
public T next() {
TreeNode<T> node = queue.poll();
for (int i = 0; i < node.childrenCount(); i++) {
queue.offer(node.getChild(i));
}
return node.getValue();
}
}
7.2 并行迭代器
利用多核CPU优势实现并行遍历:
java复制public class ParallelProductIterator implements ProductIterator {
private ExecutorService executor = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors());
private List<Future<Product>> futures = new ArrayList<>();
@Override
public boolean hasNext() {
// 并行检查各个数据源
return futures.stream().anyMatch(f -> !f.isDone());
}
@Override
public Product next() {
// 获取最先完成的结果
CompletableFuture<Product> any = CompletableFuture.anyOf(
futures.toArray(new CompletableFuture[0]));
return any.join();
}
}
7.3 不可变迭代器
对于需要防止并发修改的场景:
java复制public class ImmutableProductIterator implements ProductIterator {
private final List<Product> snapshot;
private int index = 0;
public ImmutableProductIterator(Iterable<Product> products) {
this.snapshot = Collections.unmodifiableList(
StreamSupport.stream(products.spliterator(), false)
.collect(Collectors.toList()));
}
@Override
public boolean hasNext() {
return index < snapshot.size();
}
@Override
public Product next() {
if (!hasNext()) throw new NoSuchElementException();
return snapshot.get(index++);
}
}
迭代器模式的价值在现代编程中不仅没有减弱,反而因为分布式系统和异构数据源的普及变得更加重要。理解其本质后,你会发现它无处不在——从数据库驱动到响应式编程,从集合框架到流处理,迭代器模式始终是解耦遍历逻辑与数据结构的利器。
