Skip to content

迭代器模式

引言

在软件系统中,当需要统一访问不同结构的集合对象(如数组、链表、树形结构)时,直接暴露内部存储逻辑会导致代码重复强耦合。迭代器模式通过提供标准遍历接口,实现集合元素的按需访问,成为数据遍历的"通用遥控器"。

诞生背景

GoF在《设计模式》中提出迭代器模式,解决三大痛点:

  • 遍历方式暴露:客户端需了解集合内部结构(如链表next指针)
  • 遍历逻辑耦合:相同遍历逻辑重复出现在多个客户端
  • 多集合支持困难:无法用统一方式处理数组/树/图等不同结构

演进过程

  • GoF基础(1994):确立核心角色(迭代器接口、具体迭代器)
  • 语言级集成:Java的java.util.Iterator/PHP的Iterator接口成为标准
  • 现代演进
    • 函数式编程引入惰性迭代(如Java Stream API)
    • 生成器实现(PHP的yield关键字)

核心概念

  • 迭代器(Iterator)
    • 定义访问元素的接口(hasNext(), next()
  • 具体迭代器(ConcreteIterator)
    • 实现特定集合的遍历逻辑
  • 聚合对象(Aggregate)
    • 定义创建迭代器的方法(createIterator()
  • 客户端(Client)
    • 通过迭代器接口访问元素,不依赖集合实现

通用实现

Java 实现

java
// 迭代器接口
interface Iterator<T> {
    boolean hasNext();
    T next();
}

// 聚合对象接口
interface Aggregate<T> {
    Iterator<T> createIterator();
}

// 具体聚合对象:数组集合
class ArrayCollection<T> implements Aggregate<T> {
    private T[] items;

    public ArrayCollection(T[] items) {
        this.items = items;
    }

    @Override
    public Iterator<T> createIterator() {
        return new ArrayIterator<>(items);
    }
}

// 具体迭代器:数组迭代器
class ArrayIterator<T> implements Iterator<T> {
    private T[] items;
    private int position = 0;

    public ArrayIterator(T[] items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        return position < items.length;
    }

    @Override
    public T next() {
        return items[position++];
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        String[] data = {"A", "B", "C"};
        Aggregate<String> collection = new ArrayCollection<>(data);
        Iterator<String> it = collection.createIterator();
        
        while(it.hasNext()) {
            System.out.println(it.next()); // A → B → C
        }
    }
}

PHP 实现

php
// 迭代器接口
interface IteratorInterface {
    public function hasNext(): bool;
    public function next();
}

// 聚合对象接口
interface Aggregate {
    public function createIterator(): IteratorInterface;
}

// 具体聚合对象:链表集合
class LinkedList implements Aggregate {
    private array $items = [];

    public function addItem($item): void {
        $this->items[] = $item;
    }

    public function createIterator(): IteratorInterface {
        return new LinkedListIterator($this->items);
    }
}

// 具体迭代器:链表迭代器
class LinkedListIterator implements IteratorInterface {
    private array $items;
    private int $position = 0;

    public function __construct(array $items) {
        $this->items = $items;
    }

    public function hasNext(): bool {
        return $this->position < count($this->items);
    }

    public function next() {
        return $this->items[$this->position++];
    }
}

// 客户端
$list = new LinkedList();
$list->addItem("X");
$list->addItem("Y");
$iterator = $list->createIterator();

while($iterator->hasNext()) {
    echo $iterator->next() . "\n"; // X → Y
}

应用场景

  • 统一遍历接口:处理不同结构的集合(数组/树/图)
  • 封装集合实现:隐藏集合内部存储细节
  • 并行遍历:支持同一集合的多个独立遍历
  • 延迟加载:按需获取元素(如数据库分页查询)

案例:图书馆目录系统

Java 实现

java
// 图书类
class Book {
    private String title;
    public Book(String title) { this.title = title; }
    public String getTitle() { return title; }
}

// 图书目录(树形结构)
class BookCatalog implements Aggregate<Book> {
    private List<Book> books = new ArrayList<>();
    
    public void addBook(Book book) {
        books.add(book);
    }

    @Override
    public Iterator<Book> createIterator() {
        return new BookIterator(books);
    }
}

// 图书迭代器(支持过滤)
class BookIterator implements Iterator<Book> {
    private List<Book> books;
    private int index = 0;
    private String filter;

    public BookIterator(List<Book> books) {
        this(books, null);
    }

    public BookIterator(List<Book> books, String filter) {
        this.books = books;
        this.filter = filter;
    }

    @Override
    public boolean hasNext() {
        while (index < books.size()) {
            if (filter == null || books.get(index).getTitle().contains(filter)) 
                return true;
            index++;
        }
        return false;
    }

    @Override
    public Book next() {
        return books.get(index++);
    }
}

// 客户端:查找含"Design"的书
BookCatalog catalog = new BookCatalog();
catalog.addBook(new Book("Design Patterns"));
catalog.addBook(new Book("Clean Code"));
Iterator<Book> it = new BookIterator(catalog, "Design");
while(it.hasNext()) {
    System.out.println(it.next().getTitle()); // 输出: Design Patterns
}

PHP 实现

php
// 图书类
class Book {
    private string $title;
    public function __construct(string $title) {
        $this->title = $title;
    }
    public function getTitle(): string {
        return $this->title;
    }
}

// 图书目录(组合结构)
class BookCatalog implements Aggregate {
    private array $categories = [];

    public function addCategory(string $name, array $books): void {
        $this->categories[$name] = $books;
    }

    public function createIterator(): IteratorInterface {
        return new CategoryIterator($this->categories);
    }
}

// 分类迭代器(深度优先遍历)
class CategoryIterator implements IteratorInterface {
    private array $categories;
    private array $stack = [];

    public function __construct(array $categories) {
        $this->categories = $categories;
        $this->stack = array_reverse($categories);
    }

    public function hasNext(): bool {
        return !empty($this->stack);
    }

    public function next() {
        $current = array_pop($this->stack);
        if (is_array($current)) {
            $this->stack = array_merge(
                $this->stack, 
                array_reverse($current)
            );
            return $this->next();
        }
        return $current;
    }
}

// 客户端
$catalog = new BookCatalog();
$catalog->addCategory("Design", [new Book("Patterns"), new Book("Architecture")]);
$catalog->addCategory("Programming", [new Book("PHP 8"), new Book("Java 17")]);

$iterator = $catalog->createIterator();
while($iterator->hasNext()) {
    $book = $iterator->next();
    echo $book->getTitle() . "\n"; 
    // 输出: Patterns → Architecture → PHP 8 → Java 17
}

优点

  • 解耦遍历:客户端与集合实现分离
  • 多态迭代:相同接口处理不同集合结构
  • 并行遍历:支持多个独立的遍历过程
  • 延迟执行:按需获取元素节省资源

缺点

  • 性能开销:迭代器对象创建增加内存消耗
  • 访问限制:难以直接访问特定位置元素
  • 修改风险:遍历中修改集合可能导致异常

扩展

  1. 过滤迭代器
java
class FilterIterator implements Iterator<T> {
    private Iterator<T> source;
    private Predicate<T> filter;
    // 实现条件过滤的hasNext/next
}
  1. 并发迭代器
    • 使用快照机制防止ConcurrentModificationException
  2. 组合迭代器
    • 嵌套迭代器处理树形结构(如文件系统遍历)

模式协作

  • 与组合模式:迭代树形结构(如DirectoryIterator
  • 与工厂方法:聚合对象使用工厂创建迭代器
  • 与备忘录:实现迭代状态保存/恢复

延伸思考

  1. 语言级支持
  • Java的Iterable接口+增强for循环
  • PHP的foreach背后自动调用Iterator接口
  1. 函数式编程
  • Java Stream API的filter()/map()即链式迭代器
  1. 无限序列
  • 生成器实现斐波那契数列迭代
php
function fibonacci() {
    $a = 0; $b = 1;
    while(true) {
        yield $a;
        [$a, $b] = [$b, $a + $b];
    }
}

总结

迭代器模式是集合访问的抽象层,通过标准化遍历接口,实现"透明访问集合元素"的目标。其核心价值在于:遍历逻辑与数据结构的解耦统一访问协议的建立。从简单数组到复杂树形结构,迭代器模式为数据遍历提供了优雅的通用解决方案。